/* ------------------------------------------------------------------
     The two faces, served from this folder. Everything else about Acquity
     runs on this machine; the type had no business being the exception.
     Offline, a CDN font leaves the page without its voice.

     The sans is Open Sans, as a variable font so a real 600 exists: PT Sans
     carries only 400 and 700, and asking it for a 600 got a 700. PT Serif still
     sets the names of things. PT Sans stays in the stack as a fallback.
     ------------------------------------------------------------------ */
  @font-face {   /* latin */
    font-family: 'Open Sans';
    font-style: normal;
    font-weight: 400 700;
    font-stretch: 100%;
    font-display: swap;
    src: url(/fonts/opensans-var-latin.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 {   /* latin-ext */
    font-family: 'Open Sans';
    font-style: normal;
    font-weight: 400 700;
    font-stretch: 100%;
    font-display: swap;
    src: url(/fonts/opensans-var-latin-ext.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 {   /* latin */
    font-family: 'PT Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url(/fonts/ptsans-400-latin.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 {   /* latin */
    font-family: 'PT Sans';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url(/fonts/ptsans-700-latin.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 {   /* latin-ext */
    font-family: 'PT Serif';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url(/fonts/ptserif-400-latin-ext.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 {   /* latin */
    font-family: 'PT Serif';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url(/fonts/ptserif-400-latin.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;
  }

  /* ------------------------------------------------------------------
     Acquity "the desk"

     Light, and only light. The page is a soft grey and everything on it is
     a surface lifted a shade off it. One grey family, near-neutral: no
     warm greys and no cool greys, nothing that reads as a tint until a
     score tier says so.

     One rule holds the whole design together: colour is data. Chrome is
     ink on paper; chroma is reserved for score tiers and save outcomes.
     If something is coloured, it means something.

     Type is two faces. PT Serif 400 sets the names of things: the mark, the
     desk, a deal. Open Sans does everything else, and it ships as a variable
     face, so every weight from 400 to 700 is real and a 600 is a genuine soft
     bold rather than a synthesised one. PT Sans stays in the stack as a
     fallback for a machine that has neither.
     ------------------------------------------------------------------ */
  :root {
    --void:   #f9f9f9;   /* the page: soft grey, near-neutral */
    --desk:   #ffffff;   /* text and fills that sit on ink or on a score tier */
    --panel:  #ffffff;   /* cards, drawers, anything lifted off the page */
    --raised: #f1f1f1;   /* inputs, and a row under the cursor */
    --line:   #ededed;   /* a border you are meant to see */
    --hair:   #f3f3f3;   /* one you are not */

    --ink:    #171717;   /* what you read */
    --say:    #5f5f5f;   /* what supports it */
    --quiet:  #767676;   /* labels, units, the parts you skim */

    /* Data-bearing chroma: score tiers, used nowhere decorative. Darkened
       for paper, and darkened again until each clears the contrast a figure
       being read deserves: these are numbers, not decoration. */
    --pine:  #2e7d5b;
    --brass: #8f7027;
    --clay:  #a34a33;

    /* The old names, kept pointing at the new ones. Ink on paper is literal
       again: the palette went dark for a while and has come back, and every
       rule written as "ink on paper" reads correctly either way up. */
    --paper: var(--void);
    --rule:  var(--line);
    --rule-soft: var(--hair);

    --press: #000000;    /* a primary control, pressed past its ink */
    --wash:  #dedede;    /* selected text, and the scrollbar thumb */

    /* Lift, one recipe per job. Every shadow on the page is one of these;
       nothing writes a raw rgba for a surface of its own. The values are the
       ink itself, thinned, so a shadow is never a second colour. */
    --shadow-sheet: 0 2px 14px rgba(23, 23, 23, .16);   /* the page sheet under the header */
    --shadow-menu:  0 8px 28px rgba(23, 23, 23, .12);   /* menus and the modal */
    --shadow-toast: 0 6px 24px rgba(23, 23, 23, .07);   /* the toast, the lightest lift */
    --shadow-hair:  0 1px 0 var(--hair);                /* a sticky head's hairline, not a lift */
    --scrim: rgba(23, 23, 23, .32);                     /* what the modal sits on */

    /* Motion is a budget: two durations and two curves, and nothing picks its
       own. A control changes on --dur; something entering or leaving takes
       --dur-slow. */
    --dur: .15s;
    --dur-slow: .18s;
    --ease: ease;
    --ease-pop: cubic-bezier(.2, .7, .2, 1);

    --r:     8px;        /* small controls */
    --r-field: 12px;     /* fields: one step softer than a control */
    --r-lg:  16px;       /* cards, and anything with a surface */
    --r-pill: 999px;     /* buttons, and the stage pills */

    /* Every control on the page is one of two heights. --control-h is the
       standard, and the tap minimum; --control-sm is the compact chrome that
       sits in a header or a card head, lifted to the tap minimum by touch. */
    --field-bg: var(--panel);
    --field-line: #dcdcdc;
    --field-line-hover: #b6b6b6;
    --control-h: 44px;
    --control-sm: 32px;

    --gutter: 24px;
    --tap: 44px;
    --app-max: 900px;     /* the content column never gets wider than this */
    --head-h: calc(54px + env(safe-area-inset-top));   /* the sticky header's height */

    /* The logo's face, and the face for everything else. One for the names
       of things, one for the room around them. */
    --display: 'PT Serif', Georgia, 'Times New Roman', serif;
    --sans: 'Open Sans', 'PT Sans', system-ui, -apple-system, sans-serif;

    /* Type scale. One ramp; everything on the page takes a step from it. Eight
       steps, and nothing invents a ninth. The half-pixel sizes that used to be
       scattered through this file were the whole reason type read as
       misaligned: nothing shared a rhythm with anything else. Scores keep
       one decimal everywhere, so the same deal reads the same in the ledger,
       on a card and on its sheet. */
    --t-hero:  clamp(26px, 3.8vw, 38px);   /* the desk's name, a deal's name */
    --t-page:  clamp(22px, 3.8vw, 34px);   /* a view's title: 4px under the hero */
    --t-figure: 28px;                      /* a headline number */
    --t-title: 17px;                       /* section and modal heads */
    --t-card:  19px;                       /* a card's head on home */
    --t-sub:   16px;                       /* block heads, a lead line, the nav */
    --t-tab:   15px;                       /* settings sub-tabs */
    --t-body:  14px;                       /* reading, forms */
    --t-ui:    13px;                       /* controls, rows, nav */
    --t-meta:  12px;                       /* supporting facts */
    --t-label: 10px;                       /* eyebrows, uppercase */

    --lh-hero:  1.06;
    --lh-title: 1.2;
    --lh-body:  1.5;
    --ls-hero:  -0.015em;
    --ls-title: -0.01em;
    --ls-tight: -0.02em;
    --ls-label: 0.12em;
  }

  * { box-sizing: border-box; }
  html { -webkit-text-size-adjust: 100%; background: var(--void); }
  body {
    margin: 0;
    background: var(--void);
    color: var(--ink);
    font-family: var(--sans);
    font-weight: 400;
    font-size: var(--t-body);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    min-height: 100vh;
    display: flex; flex-direction: column;
  }
  button, input, select, textarea { font: inherit; color: inherit; }
  button { cursor: pointer; }
  a { color: inherit; }
  ::selection { background: var(--wash); }
  /* The scrollbar is chrome, and chrome is quiet. */
  * { scrollbar-color: var(--wash) transparent; scrollbar-width: thin; }

  /* ---------- on a phone, an app rather than a page ----------
     What gives a web app away on a phone is never the design. It is a handful
     of behaviours a browser provides because it is showing a document, and a
     desk has no use for any of them: a grey flash under every tap, a long
     press offering to select the row you meant to open, a downward swipe that
     reloads the lot, and a field that zooms the whole screen when you touch
     it. Turned off here, one at a time, and what they were standing in for is
     put back below. */
  html { overscroll-behavior-y: none; }              /* no pull to reload */
  body { -webkit-tap-highlight-color: transparent; }
  button, .stage, .step { touch-action: manipulation; -webkit-touch-callout: none; }
  /* Chrome is not text. What the desk holds still is: a broker's number has to
     come off the page and into the phone app. */
  .eyebrow, .stage, .mark, .pager,
  .btn-solid, .btn-ghost, .btn-text { -webkit-user-select: none; user-select: none; }
  /* A panel that scrolls keeps its scrolling to itself. */
  .modal, .modal-body { overscroll-behavior: contain; }

  @media (hover: none) {
    /* Below 16px, Safari zooms the page when a field takes focus and leaves
       the app scrolled sideways with no way back but a pinch. */
    .field input, .field select, .field textarea,
    .bar input[type="search"], .bar select, .people-search { font-size: var(--t-sub); }

    /* A finger has no hover, so every press was landing on a screen that did
       not move. This is what the tap flash was standing in for, done properly:
       the surface the thing already uses, for exactly as long as you hold it. */
    .stage:active, .btn-ghost:active { background: var(--raised); }
    .btn-solid:active { background: var(--press); }
    .modal-x:active { color: var(--ink); }

    /* A finger needs a bigger target than a pointer. The few controls that
       ship under the tap minimum on the desk are lifted to it here. */
    .topnav button { padding: 12px; }
    .pager-step { width: var(--tap); height: var(--tap); }
    .modal-x { min-height: var(--tap); }
  }

  /* Numerals are aligned down a column by their right edge, which is what makes
     a list of prices comparable at a glance. */
  .num {
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--ls-title);
  }
  .eyebrow {
    font-weight: 600;
    font-size: var(--t-label);
    text-transform: uppercase; letter-spacing: var(--ls-label);
    color: var(--quiet);
  }
  :focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; border-radius: 4px; }

  /* The page's white sheet, full bleed under the grey header, and the column
     of content held to a reading width inside it. The sheet carries the top
     corners and the shadow; the column carries only the gutter. It is at least
     a screen tall and lays itself out top to bottom, so the pager can sit at
     its foot instead of wherever five rows happen to end. */
  .app {
    flex: 1; display: flex; flex-direction: column;
    margin-top: 10px;
    background: var(--desk);
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    box-shadow: var(--shadow-sheet);
  }
  .shell {
    width: 100%; max-width: var(--app-max); margin: 0 auto;
    padding: 0 var(--gutter) calc(28px + env(safe-area-inset-bottom));
    flex: 1; display: flex; flex-direction: column;
  }
  .shell > #rowsHost { flex: 1; display: flex; flex-direction: column; min-width: 0; }

  /* ---------- the way in ----------
     Signing in is its own page, not a modal over the desk: with no session
     there is nothing behind it to show. The mark, the two fields, and the one
     button. Nothing else. */
  body.locked > .topbar, body.locked > .app,
  body.booting > .topbar, body.booting > .app { display: none; }
  .login { min-height: 100vh; display: grid; place-items: center; padding: var(--gutter); }
  .login[hidden] { display: none; }
  .login-inner { width: 100%; max-width: 320px; display: flex; flex-direction: column; gap: 28px; }
  .login .mark { justify-content: center; font-size: 30px; }
  .login form { display: flex; flex-direction: column; }
  .login .field { margin-bottom: 14px; }
  .login .btn-solid { width: 100%; }
  .login .state { display: block; margin-top: 12px; text-align: center; }

  /* ---------- the header ----------
     Full bleed: the mark at the window's left edge, you at its right, the four
     views between them. The desk below it is the only thing held to a reading
     width. */
  .topbar { position: sticky; top: 0; z-index: 20; background: var(--void); }
  .topbar-inner {
    max-width: 90%; margin: 0 auto;
    display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 16px;
    padding: calc(12px + env(safe-area-inset-top)) var(--gutter) 10px;
  }
  .topnav { display: flex; gap: 2px; justify-self: center; }
  .topright { display: flex; align-items: center; gap: 10px; justify-self: end; min-width: 0; }
  .topnav button {
    background: none; border: 0; padding: 8px 12px;
    font-size: var(--t-body); font-weight: 600; line-height: 1; color: var(--say);
    transition: color var(--dur) var(--ease);
  }
  .topnav button:hover { color: var(--ink); }
  .topnav button[aria-pressed="true"] { color: var(--ink); font-weight: 600; }
  .account { display: flex; align-items: center; gap: 10px; font-size: var(--t-ui); color: var(--say); }
  @media (max-width: 620px) { .topnav button { padding: 8px; } }

  /* The lockup: the drawn lambda, then the word in the display serif. The mark
     is the phone's own app icon and stands taller than the letters beside it,
     the way a mark should, with its feet on the baseline. Together they read
     Acquity, which is what the heading is named. */
  .mark { display: flex; align-items: baseline; gap: 2px; min-width: 0; margin: 0; font-size: 26px; line-height: 1; }
  .mark .lambda { height: 1em; width: auto; flex: none; fill: currentColor; display: block; }
  .mark .word {
    font-family: var(--display); font-weight: 400;
    font-size: 1em; line-height: 1; letter-spacing: var(--ls-title);
  }

  /* ---------- the head of a view ----------
     Its title, and nothing else. A hero used to sit here, forty-odd pixels of
     greeting that said nothing on purpose. Rule four says the interface is
     quiet and the data is loud, and the loudest thing on the page was the
     one part carrying no data. */
  .read { display: flex; align-items: center; gap: 16px; padding: 24px 0 20px; }
  .read .spacer { flex: 1; }

  /* ---------- the summary ----------
     The greeting is the title now, and the date sits at the far edge of the
     same line. The desk's name used to sit here too, but the desk is the page
     you are already on: naming it twice bought nothing. */
  .home-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 6px 16px; flex-wrap: wrap; padding: 34px 0 32px;
  }
  .home-head h2 {
    margin: 0; font-family: var(--display); font-weight: 400;
    font-size: var(--t-hero); line-height: var(--lh-hero); letter-spacing: var(--ls-hero);
    text-wrap: balance; overflow-wrap: anywhere;
  }
  .home-date { flex: none; font-size: var(--t-ui); color: var(--quiet); }

  /* ---------- home: two blocks ----------
     The heading and its one action sit above the card rather than inside it:
     the card is the surface holding the data, and the name of the thing is not
     data. The action is a pill with an arrow, because it goes somewhere. */
  .home-grid { display: flex; flex-direction: column; gap: 26px; }
  .card-block { min-width: 0; }
  .card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
  .card-head h3 { margin: 0; font-family: var(--display); font-weight: 400; font-size: var(--t-card); line-height: var(--lh-title); }
  .card-action {
    flex: none; display: inline-flex; align-items: center; gap: 6px;
    background: var(--ink); border: 1px solid var(--ink); border-radius: var(--r-pill);
    height: var(--control-sm); padding: 0 14px;
    font-size: var(--t-ui); font-weight: 600; color: var(--desk);
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
  }
  .card-action:hover { background: var(--press); border-color: var(--press); }
  /* One filled action per view. A second card action on the same screen is the
     same shape, outlined, so the primary still reads as the primary. */
  .card-action.ghost { background: var(--panel); border-color: var(--field-line); color: var(--ink); }
  .card-action.ghost:hover { background: var(--raised); border-color: var(--field-line-hover); }
  .card-action svg { width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

  .card {
    background: var(--panel); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 22px 24px; min-width: 0;
  }
  .card > .eyebrow { display: block; margin-bottom: 14px; }
  .card .hint { margin: 0; }
  .card-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
  .note { margin: 0; font-size: var(--t-body); line-height: var(--lh-body); }
  .note b { font-weight: 600; }
  .note.quiet { color: var(--quiet); font-size: var(--t-ui); }
  /* The notifications card opens with a mark: it is a notice, and the mark says
     so before the sentence does. */
  .note-card { flex-direction: row; align-items: center; gap: 12px; }
  .note-icon { flex: none; width: 22px; height: 22px; fill: none; stroke: var(--quiet); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
  .note-text { min-width: 0; }

  /* The list card carries no inset of its own: the rows bring their own, so a
     hairline and a hover run the full width of the surface instead of stopping
     short at a padding edge. */
  .card-rows { padding: 8px 0; overflow: hidden; }
  .hot {
    display: flex; align-items: center; gap: 16px; width: 100%;
    text-align: left; background: none; border: 0; padding: 14px 24px;
    border-top: 1px solid var(--hair);
  }
  .hot:first-child { border-top: 0; }
  .hot:hover { background: var(--raised); }
  .hot:focus-visible { outline-offset: -2px; }
  .hot:hover .hot-main b { text-decoration: underline; text-underline-offset: 3px; }
  .hot .score { min-width: 30px; text-align: left; flex: none; font-size: var(--t-title); }
  .hot-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .hot-main b { font-size: var(--t-body); font-weight: 600; }
  .hot-main span { font-size: var(--t-ui); color: var(--quiet); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

  /* ---------- the stage filters ----------
     Five counts that double as filters, one line of pills. They were tiles,
     four fifths of which read zero on any ordinary day: ninety pixels spent
     saying nothing four times over. A pill says the same thing in one line,
     wraps rather than snapping to a grid on a phone, and the one you have
     pinned still reads as a state, the way a pinned control anywhere on the
     desk does. */
  .stages { display: flex; flex-wrap: wrap; gap: 8px; padding: 18px 0 8px; }
  .stage {
    display: inline-flex; align-items: center; gap: 8px;
    background: var(--panel); border: 1px solid var(--field-line);
    border-radius: var(--r-pill); padding: 0 16px; min-height: var(--tap);
    transition: border-color var(--dur) var(--ease);
  }
  .stage:hover { border-color: var(--field-line-hover); }
  .stage[aria-pressed="true"] { border-color: var(--ink); }
  .stage-n { font-size: var(--t-sub); font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; }
  .stage-l { font-size: var(--t-ui); line-height: 1; color: var(--quiet); }

  /* ---------- toolbar ---------- */
  .bar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; padding: 20px 0 16px; }
  .bar input[type="search"], .bar select {
    background: var(--field-bg); border: 1px solid var(--field-line); border-radius: var(--r-field);
    padding: 0 14px; height: var(--control-h); font-size: var(--t-body);
    -webkit-appearance: none; appearance: none;
    transition: border-color var(--dur) var(--ease);
  }
  .bar input[type="search"]:hover, .bar select:hover { border-color: var(--field-line-hover); }
  /* A native select keeps its own radius and its own arrow whatever the rule
     says, so both are drawn here instead. The arrow's grey is written into
     the URI: move it when --quiet moves. */
  .bar select {
    padding-right: 38px;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23767676' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 14px center; background-size: 11px;
  }
  .bar input[type="search"] { flex: 1 1 200px; min-width: 0; }
  .bar input[type="search"]::placeholder { color: var(--quiet); }
  .bar .spacer { flex: 1 1 auto; }

  /* The three narrowings live behind one mark, so the bar stays a bar:
     search, filter, add. The mark inks like a selected control while a
     filter is on, so a narrowed list never looks like the whole ledger. */
  .filter { position: relative; flex: none; }
  .filter-btn {
    display: grid; place-items: center; width: var(--control-h); height: var(--control-h);
    background: var(--field-bg); border: 1px solid var(--field-line); border-radius: var(--r-field);
    color: var(--say);
    transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .filter-btn:hover { border-color: var(--field-line-hover); color: var(--ink); }
  .filter-btn[aria-pressed="true"] { border-color: var(--ink); color: var(--ink); }
  .filter-btn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
  .filter-menu {
    position: absolute; top: calc(100% + 8px); left: 0; z-index: 40;
    min-width: 280px; max-width: min(340px, calc(100vw - 32px));
    padding: 16px;
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
    box-shadow: var(--shadow-menu);
  }
  .filter-menu[hidden] { display: none; }
  .filter-menu select { max-width: none; flex: none; }
  .filter-clear { padding-left: 0; padding-right: 0; }
  .btn-ghost {
    background: none; border: 1px solid var(--field-line); border-radius: var(--r-pill);
    height: var(--control-h); padding: 0 14px; font-size: var(--t-ui); font-weight: 600;
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
  }
  .btn-ghost:hover { background: var(--panel); border-color: var(--field-line-hover); }

  /* ---------- the score tiers ----------
     Colour is data, and this is the only place the page spends it. An
     absent score is not a tier: it is a dash in the quiet grey. */
  .t-hi { color: var(--pine); }
  .t-mid { color: var(--brass); }
  .t-lo { color: var(--clay); }
  .t-na { color: var(--quiet); }
  /* A score is a figure you compare down a column, so it is set bold wherever
     it appears. */
  .score { font-weight: 600; }

  /* ---------- the pipeline table ----------
     The ledger as a table: one header, hairlines between rows, nothing
     boxed. The row is the way into the tear sheet. */
  .tbl { width: 100%; border-collapse: collapse; }
  .tbl th {
    text-align: left; font-size: var(--t-label); font-weight: 600;
    text-transform: uppercase; letter-spacing: var(--ls-label); color: var(--quiet);
    padding: 0 16px 10px;
  }
  .tbl th:first-child, .tbl td:first-child { padding-left: 4px; }
  .tbl th:first-child, .tbl td:first-child { text-align: right; }
  .tbl th:nth-child(3), .tbl th:nth-child(4), .tbl th:nth-child(5),
  .tbl td:nth-child(3), .tbl td:nth-child(4), .tbl td:nth-child(5) { text-align: right; }
  .tbl td { padding: 14px 16px; border-top: 1px solid var(--hair); vertical-align: middle; }
  .tbl tbody tr { cursor: pointer; transition: background var(--dur) var(--ease); }
  .tbl tbody tr:hover, .tbl tbody tr:focus-visible { background: var(--raised); }
  .tbl .is-passed { opacity: .42; }
  .tbl .t-name { min-width: 0; }
  .tbl .t-name b { display: block; font-size: var(--t-body); font-weight: 600; }
  .tbl .t-name span { font-size: var(--t-ui); color: var(--quiet); }
  .tbl .score { text-align: right; font-size: var(--t-title); }
  .tbl .num { font-size: var(--t-body); }
  .tbl .mult { font-weight: 600; }
  .tbl em { font-style: normal; color: var(--quiet); }

  /* The header row can say what the columns are only while there is room
     for columns. Under that, each row becomes two lines: the score and the
     name, then the money with its labels back beside it, which is the one
     thing the header can no longer say for it. SDE drops off rather than
     crowds, the same figure the deal sheet holds anyway. */
  @media (max-width: 860px) {
    .tbl, .tbl tbody, .tbl tr, .tbl td { display: block; }
    .tbl thead { display: none; }
    .tbl tr {
      display: grid; grid-template-columns: minmax(0, 1fr) auto;
      gap: 6px 16px; padding: 16px 4px; border-top: 1px solid var(--hair);
    }
    .tbl tbody tr:first-child { border-top: 0; }
    .tbl td { padding: 0; border: 0; }
    .tbl td.t-name, .tbl td.ask, .tbl td.sde, .tbl td.mult { text-align: left; }
    .tbl td.score { grid-column: 2; grid-row: 1; }
    .tbl td.t-name { grid-column: 1; grid-row: 1; }
    .tbl td.t-name b { overflow-wrap: anywhere; }
    .tbl td.ask, .tbl td.mult { grid-row: 2; display: flex; align-items: baseline; gap: 8px; }
    .tbl td.ask { grid-column: 1; }
    .tbl td.mult { grid-column: 2; justify-content: flex-end; }
    .tbl td.sde { display: none; }
    .tbl td.ask::before, .tbl td.mult::before {
      font-size: var(--t-label); font-weight: 600; text-transform: uppercase;
      letter-spacing: var(--ls-label); color: var(--quiet);
    }
    .tbl td.ask::before { content: "Asking"; }
    .tbl td.mult::before { content: "Multiple"; }
  }

  /* ---------- the pager ---------- */
  .pager {
    display: flex; align-items: center; gap: 10px;
    margin-top: auto; padding-top: 22px;
  }
  .pager .spacer { flex: 1; }
  .pager-at, .pager-n {
    font-weight: 600;
    font-size: var(--t-label); letter-spacing: var(--ls-label);
    text-transform: uppercase; color: var(--quiet);
  }
  .pager-n { min-width: 54px; text-align: center; }
  .pager-step {
    background: none; border: 1px solid var(--field-line); border-radius: var(--r);
    width: var(--control-sm); height: var(--control-sm); color: var(--say);
    display: grid; place-items: center;
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
  }
  .pager-step svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
  .pager-step:hover:not([disabled]) { background: var(--panel); border-color: var(--field-line-hover); color: var(--ink); }
  .pager-step[disabled] { opacity: .3; cursor: default; }

  /* ---------- empty ----------
     An empty screen says what to do next, or that the desk is still being
     read: it never claims to be empty of deals it has not finished loading. */
  .empty { padding: 62px 0 76px; max-width: 44ch; margin: 0 auto; text-align: center; }
  .empty h2 { margin: 0 0 8px; font-family: var(--sans); font-weight: 400; font-size: var(--t-title); line-height: var(--lh-title); }
  .empty p { margin: 0 0 20px; color: var(--quiet); font-size: var(--t-body); line-height: 1.6; }
  .empty p:last-child { margin-bottom: 0; }

  /* ---------- forms ---------- */
  .field { display: block; margin-bottom: 12px; }
  .field span { display: block; font-size: var(--t-meta); color: var(--quiet); margin-bottom: 4px; }
  .field input, .field select, .field textarea {
    width: 100%; background: var(--field-bg); border: 1px solid var(--field-line); border-radius: var(--r-field);
    padding: 11px 13px; font-size: var(--t-body);
    transition: border-color var(--dur) var(--ease);
  }
  .field input:hover, .field select:hover, .field textarea:hover { border-color: var(--field-line-hover); }
  /* The note grows with what is written in it, where the browser knows how;
     where it does not, the field simply keeps its fixed height. */
  .field textarea { min-height: 84px; resize: vertical; line-height: 1.55; field-sizing: content; }
  .field select {
    -webkit-appearance: none; appearance: none; padding-right: 38px;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23767676' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 14px center; background-size: 11px;
  }
  .grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
  .hint { font-size: var(--t-meta); color: var(--quiet); line-height: 1.6; margin: 4px 0 16px; }
  .hint:last-child { margin-bottom: 0; }
  /* Buttons are quiet until pressed: the height carries the tap target, and
     the padding only needs to keep the label off the edge. */
  .btn-solid {
    background: var(--ink); color: var(--paper); border: 1px solid var(--ink); border-radius: var(--r-pill);
    height: var(--control-h); padding: 0 16px; font-size: var(--t-ui); font-weight: 600;
    transition: background var(--dur) var(--ease);
  }
  .btn-solid:hover { background: var(--press); border-color: var(--press); }
  .btn-solid[disabled] { opacity: .45; cursor: default; }
  .btn-text { background: none; border: 0; padding: 8px 12px; border-radius: var(--r-pill); font-size: var(--t-ui); font-weight: 400; color: var(--quiet); transition: background var(--dur) var(--ease), color var(--dur) var(--ease); }
  .btn-text:hover { background: var(--raised); color: var(--ink); }
  .actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 6px; }

  /* ---------- how a score was arrived at ---------- */
  .why { list-style: none; margin: 0; padding: 0; }
  .why li {
    display: flex; align-items: baseline; gap: 14px;
    padding: 8px 0; border-bottom: 1px solid var(--hair);
    font-size: var(--t-ui);
  }
  .why li:last-child { border-bottom: 0; }
  .why li span { flex: 1; min-width: 0; }
  .why li b { flex: none; color: var(--quiet); }
  .why li b.up { color: var(--pine); }
  .why li b.down { color: var(--clay); }
  .why-note { margin: 12px 0 0; font-size: var(--t-meta); color: var(--quiet); line-height: 1.6; }
  /* The working's small print, on demand: an i in the card's corner, and the
     note on hover or focus. The card keeps the figures; the footnote stays out
     of the way until it is asked for. */
  .why-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
  .why-head .eyebrow { margin: 0; }
  .info { position: relative; flex: none; display: inline-grid; place-items: center; width: 18px; height: 18px; color: var(--quiet); cursor: help; }
  .info:hover, .info:focus-visible { color: var(--ink); }
  .info svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
  .info-tip {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 30;
    width: 220px; padding: 10px 12px;
    background: var(--ink); color: var(--desk);
    border-radius: var(--r); font-size: var(--t-meta); font-weight: 400; line-height: 1.55;
    opacity: 0; visibility: hidden; transform: translateY(-3px);
    transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility var(--dur);
  }
  .info:hover .info-tip, .info:focus-visible .info-tip { opacity: 1; visibility: visible; transform: none; }

  .state { font-size: var(--t-meta); color: var(--quiet); }
  .state.ok { color: var(--pine); }
  .state.err { color: var(--clay); }

  /* ---------- outcomes ----------
     One place for every write to report itself, above the thumb on a phone and
     out of the way of the ledger on a desk. They stack downwards so the newest
     is nearest the eye, and they take themselves away. */
  .toasts {
    position: fixed; z-index: 60;
    left: 50%; transform: translateX(-50%);
    bottom: calc(24px + env(safe-area-inset-bottom));
    display: flex; flex-direction: column-reverse; gap: 8px;
    pointer-events: none;
    width: min(420px, calc(100vw - 32px));
  }
  .toast {
    background: var(--raised); color: var(--ink);
    border-radius: var(--r); padding: 14px 16px;
    font-size: var(--t-ui); font-weight: 600; line-height: 1.45;
    box-shadow: var(--shadow-toast);
    animation: toast-in var(--dur-slow) var(--ease-pop);
  }
  .toast.err { color: var(--clay); }
  .toast.going { animation: toast-out var(--dur-slow) var(--ease) forwards; }
  @keyframes toast-in { from { opacity: 0; transform: translateY(10px); } }
  @keyframes toast-out { to { opacity: 0; transform: translateY(6px); } }

  /* ---------- what a hunt found ----------
     A find is a decision, not a record: it is not in the ledger yet, and it
     leaves this list the moment you answer it. So it is drawn the way the
     ledger is drawn: one header, hairlines between the rows, nothing boxed.
     The decision is the row's one filled control, which is why the inbox is
     the exception to one primary per view. The three figures are plain type,
     right-aligned in their columns, so the money is the loud thing and the
     row is not four surfaces deep. */
  /* ---------- the inbox ----------
     The list scrolls, not the page: the header and the column headings hold
     their place while the finds move under them. */
  .finds-host { flex: 1 1 0; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
  .finds { width: 100%; table-layout: fixed; border-collapse: collapse; }
  .finds th {
    position: sticky; top: 0; z-index: 1;
    background: var(--desk); box-shadow: var(--shadow-hair);
    text-align: left; font-size: var(--t-label); font-weight: 600;
    text-transform: uppercase; letter-spacing: var(--ls-label); color: var(--quiet);
    padding: 0 16px 10px;
  }
  /* The columns are pinned so the decision never wraps under its own buttons:
     the name takes what is left, and the figures are sized for the widest
     money the desk can print. */
  .finds th:nth-child(1) { width: 60px; }
  .finds th:nth-child(3), .finds th:nth-child(4) { width: 76px; }
  .finds th:nth-child(5) { width: 96px; }
  .finds th:nth-child(6) { width: 126px; }
  .finds th:first-child, .finds td:first-child { padding-left: 4px; text-align: right; }
  .finds th:nth-child(3), .finds th:nth-child(4), .finds th:nth-child(5),
  .finds td:nth-child(3), .finds td:nth-child(4), .finds td:nth-child(5) { text-align: right; }
  .finds td { padding: 14px 16px; border-top: 1px solid var(--hair); vertical-align: middle; }
  .finds tbody tr:first-child td { border-top: 0; }
  .finds tbody tr { cursor: pointer; transition: background var(--dur) var(--ease); }
  .finds tbody tr:hover, .finds tbody tr:focus-visible { background: var(--raised); }
  .find .score { font-size: var(--t-title); }
  /* A find's name and place are one line each, always: the row is a thing you
     scan, and a row that changes height cannot be scanned. The whole string
     rides on the title attribute, which is the browser's own tooltip. */
  .find-name { min-width: 0; }
  .find-name b { display: block; font-size: var(--t-body); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .find-where { display: block; font-size: var(--t-ui); color: var(--quiet); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .find-fig { font-size: var(--t-body); font-variant-numeric: tabular-nums; }
  .find-fig em { font-style: normal; color: var(--quiet); }
  .find-do { text-align: right; }
  .find-act { display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; }

  /* The three things you can do with a find, as circles rather than words: a
     plus to add it, a minus to pass, and the square-arrow out to the listing.
     The plus is the one filled mark, because it is the answer you are hoping to
     give. Each carries its sentence in an aria-label and a title. The add and
     the pass paint their outcome on themselves before the row goes: the plus
     turns a green tick, the minus a red cross, so the answer lands in the place
     the question was asked. */
  .find-btn {
    flex: none; width: var(--tap); height: var(--tap);
    display: inline-grid; place-items: center;
    background: none; border: 1px solid var(--field-line); border-radius: var(--r-pill);
    padding: 0; color: var(--say);
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
  }
  .find-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
  .find-btn:hover { border-color: var(--field-line-hover); color: var(--ink); }
  .find-btn[disabled] { opacity: .45; cursor: default; }
  .find-btn.act-add { background: var(--ink); border-color: var(--ink); color: var(--desk); }
  .find-btn.act-add:hover { background: var(--press); border-color: var(--press); }
  .find-btn .ico-check, .find-btn .ico-x { display: none; }
  .find-act.is-accept .act-add { background: var(--pine); border-color: var(--pine); color: var(--desk); opacity: 1; }
  .find-act.is-accept .act-add .ico-plus { display: none; }
  .find-act.is-accept .act-add .ico-check { display: block; }
  .find-act.is-dismiss .act-dismiss { background: var(--clay); border-color: var(--clay); color: var(--desk); opacity: 1; }
  .find-act.is-dismiss .act-dismiss .ico-minus { display: none; }
  .find-act.is-dismiss .act-dismiss .ico-x { display: block; }
  .find.gone { opacity: 0; transition: opacity var(--dur-slow) var(--ease); }

  /* The header can say what the columns are only while there is room for
     columns. Under that a find becomes three lines: the score and the name,
     the money with its labels back beside it, then the decision, which no
     longer fits against the edge once the figures have taken the row. SDE
     drops off rather than crowds, the same figure the deal sheet holds. */
  @media (max-width: 860px) {
    .finds, .finds tbody, .finds tr, .finds td { display: block; }
    .finds thead { display: none; }
    .finds tr {
      display: grid; grid-template-columns: minmax(0, 1fr) auto;
      gap: 6px 16px; padding: 16px 4px; border-top: 1px solid var(--hair);
    }
    .finds tbody tr:first-child { border-top: 0; }
    .finds td { padding: 0; border: 0; }
    .finds td.find-name, .finds td.ask, .finds td.sde, .finds td.mult { text-align: left; }
    .finds td.score { grid-column: 2; grid-row: 1; text-align: right; }
    .finds td.find-name { grid-column: 1; grid-row: 1; }
    .finds td.ask, .finds td.mult { grid-row: 2; display: flex; align-items: baseline; gap: 8px; }
    .finds td.ask { grid-column: 1; }
    .finds td.mult { grid-column: 2; justify-content: flex-end; }
    .finds td.sde { display: none; }
    .finds td.ask::before, .finds td.mult::before {
      font-size: var(--t-label); font-weight: 600; text-transform: uppercase;
      letter-spacing: var(--ls-label); color: var(--quiet);
    }
    .finds td.ask::before { content: "Asking"; }
    .finds td.mult::before { content: "Multiple"; }
    .finds td.find-do { grid-column: 1 / -1; grid-row: 3; margin-top: 12px; text-align: left; }
    .finds td.find-do .find-act { justify-content: flex-start; flex-wrap: wrap; }
  }

  /* ---------- modal ---------- */
  .modal {
    width: min(640px, calc(100vw - 32px)); max-height: 88vh; overflow: auto;
    padding: 0; border: 0; border-radius: var(--r-lg);
    background: var(--panel); color: var(--ink);
  }
  .modal::backdrop { background: var(--scrim); }
  .modal[open] { animation: pop var(--dur-slow) var(--ease-pop); }
  @keyframes pop { from { opacity: 0; transform: translateY(8px); } }
  .modal-head {
    position: sticky; top: 0; z-index: 1; background: var(--panel);
    padding: 22px 24px 18px;
  }
  .modal-head .head-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
  .modal-head h2 { margin: 0; font-family: var(--sans); font-weight: 600; font-size: var(--t-title); line-height: var(--lh-title); letter-spacing: var(--ls-title); }
  .modal-head .eyebrow { display: block; margin-top: 4px; }
  .modal-x { background: none; border: 0; padding: 6px 8px; margin: -6px -8px -6px 0; font-size: var(--t-sub); line-height: 1; color: var(--quiet); }
  .modal-x:hover { color: var(--ink); }
  .modal-body { padding: 22px 24px 6px; }
  /* The find record opens tight: its figures are the first thing, and they do
     not need a paragraph's worth of air above or below them. */
  .find-body { padding-top: 14px; }
  .find-body .figures { margin: 0 0 14px; }
  .stack { display: grid; gap: 12px; }
  .modal-foot .spacer { flex: 1 1 auto; }
  /* Inside a modal the card chrome of a panel is one border too many, so a
     second subject is marked off with a rule and nothing else. */
  .modal-group { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--rule-soft); }
  .modal-group > .eyebrow { display: block; margin-bottom: 12px; }
  .modal-group:last-child { padding-bottom: 12px; }
  .modal-foot {
    position: sticky; bottom: 0; background: var(--panel);
    padding: 16px 24px calc(16px + env(safe-area-inset-bottom));
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  }

  /* ---------- tear sheet (detail) ---------- */
  .sheet { padding: 28px 0 0; min-width: 0; }
  .sheet-top { display: flex; align-items: center; gap: 12px; margin-bottom: 22px; }
  .sheet-top .spacer { flex: 1; }
  a.btn-ghost, a.btn-solid { display: inline-grid; place-items: center; text-decoration: none; }
  .back { background: none; border: 0; padding: 6px 0; font-size: var(--t-ui); font-weight: 600; color: var(--quiet); min-width: 0; }
  .back:hover { color: var(--ink); }
  .s-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 22px; padding-bottom: 22px; border-bottom: 1px solid var(--rule); }
  /* A deal's name is a name, and names are the display serif's one job. */
  .s-head h2 { margin: 0; font-family: var(--display); font-weight: 400; font-size: var(--t-hero); letter-spacing: var(--ls-hero); line-height: var(--lh-hero); overflow-wrap: anywhere; }
  .s-head .meta { margin-top: 8px; font-size: var(--t-ui); color: var(--quiet); }
  .s-score { text-align: right; flex: none; }
  .s-score b { display: block; font-family: var(--sans); font-weight: 600; font-size: var(--t-figure); line-height: 1; letter-spacing: var(--ls-hero); font-variant-numeric: tabular-nums; }
  .s-score span { display: block; margin-top: 6px; font-size: var(--t-label); text-transform: uppercase; letter-spacing: var(--ls-label); color: var(--quiet); }
  /* The three figures, as tiles: the same surface the cards use, so a number
     on a tile means the same thing in both places. */
  .figures { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 24px 0 28px; }
  .figures div { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 18px 20px; min-width: 0; }
  .figures span {
    display: block; margin-bottom: 8px;
    font-weight: 600;
    font-size: var(--t-label);
    text-transform: uppercase; letter-spacing: var(--ls-label); color: var(--quiet);
  }
  .figures b { font-size: var(--t-title); font-weight: 500; letter-spacing: var(--ls-tight); font-variant-numeric: tabular-nums; }

  /* What you do with the deal, and what is already true about it. */
  .sheet-grid { display: grid; gap: 28px; align-items: start; }
  .sheet-main > .block:first-child { padding-top: 0; }
  .sheet-aside { display: grid; gap: 8px; }
  @media (min-width: 861px) {
    .sheet-grid { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); gap: 40px; }
  }

  .block { padding: 22px 0; border-bottom: 1px solid var(--rule); }
  .block > .eyebrow { display: block; margin-bottom: 10px; }
  .block p { margin: 0; font-size: var(--t-body); line-height: 1.65; max-width: 68ch; }

  /* A label and its value, down a narrow column. */
  .facts { margin: 0; display: grid; gap: 12px; }
  .facts div { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
  .facts dt { flex: none; font-size: var(--t-meta); color: var(--quiet); }
  .facts dd { margin: 0; font-size: var(--t-ui); text-align: right; overflow-wrap: anywhere; }
  .facts a { text-underline-offset: 3px; }

  /* ---------- the stage track ----------
     One chain rather than five loose buttons, because the pipeline is a real
     sequence and where a deal sits in it is the fact worth showing. Each step
     is cut with a point on its right and a notch on its left, and they overlap
     so one seats into the next. */
  .track { --notch: 14px; display: flex; border-radius: var(--r-field); overflow: hidden; }
  .step {
    position: relative;
    flex: 1 1 0; min-width: 0;
    background: var(--field-line); color: var(--quiet);   /* the shape's edge is the border */
    border: 0; height: var(--tap);
    padding: 0 10px 0 calc(var(--notch) + 12px);
    font-size: var(--t-ui); font-weight: 600; text-align: left;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    clip-path: polygon(0 0, calc(100% - var(--notch)) 0, 100% 50%, calc(100% - var(--notch)) 100%, 0 100%, var(--notch) 50%);
    margin-left: calc(var(--notch) * -1);
    transition: color var(--dur) var(--ease);
  }
  /* The fill sits a pixel inside the shape, so what shows is a border that
     follows the same notch: every step but the one you are on is outlined. */
  .step::before {
    content: ""; position: absolute; inset: 1px; background: var(--panel);
    clip-path: polygon(0 0, calc(100% - var(--notch)) 0, 100% 50%, calc(100% - var(--notch)) 100%, 0 100%, var(--notch) 50%);
    transition: background var(--dur) var(--ease);
  }
  .step > span { position: relative; display: block; overflow: hidden; text-overflow: ellipsis; }
  /* The chain has to start flat and end flat, or it points in from nowhere and
     out to nothing. */
  .step:first-child {
    margin-left: 0; padding-left: 14px;
    clip-path: polygon(0 0, calc(100% - var(--notch)) 0, 100% 50%, calc(100% - var(--notch)) 100%, 0 100%);
  }
  .step:first-child::before {
    clip-path: polygon(0 0, calc(100% - var(--notch)) 0, 100% 50%, calc(100% - var(--notch)) 100%, 0 100%);
    border-radius: calc(var(--r-field) - 1px) 0 0 calc(var(--r-field) - 1px);
  }
  .step:last-child {
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, var(--notch) 50%);
  }
  .step:last-child::before {
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, var(--notch) 50%);
    border-radius: 0 calc(var(--r-field) - 1px) calc(var(--r-field) - 1px) 0;
  }
  .step:hover { color: var(--say); }
  .step:hover::before { background: var(--raised); }
  .step.done { color: var(--say); }
  .step.done::before { background: var(--raised); }
  .step.at { color: var(--desk); }
  .step.at::before { background: var(--ink); }
  /* Passed on: still the same track, but nothing on it is true any more. */
  .track.off .step { opacity: .4; }
  .track.off .step.at { color: var(--quiet); }
  .track.off .step.at::before { background: var(--panel); }

  /* ---------- settings ----------
     Desks, the mandate, the account: a view rather than a modal, so nothing
     halfway through typing sits behind an overlay.

     The desk tab is a portrait of the desk itself: its name, the four numbers
     that say how it is doing, then the two things you set on it, strategy and
     the hunt, each a card with its own way in. Switching desks lives in the
     header now, so nothing here repeats it. */
  .desk-hero {
    position: relative;
    background: var(--panel); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 24px; margin-bottom: 14px;
  }
  .desk-hero h3 {
    margin: 8px 0 14px; padding-right: 44px; font-family: var(--display); font-weight: 400;
    font-size: var(--t-page); line-height: var(--lh-hero); letter-spacing: var(--ls-hero);
    overflow-wrap: anywhere;
  }
  /* The cog opens the desk's own settings: its name, and the way to remove it.
     Rare, and beside the desk rather than in the flow of the page. */
  .desk-cog {
    position: absolute; top: 16px; right: 16px;
    width: var(--tap); height: var(--tap);
    display: grid; place-items: center;
    background: none; border: 0; border-radius: var(--r-pill); color: var(--quiet);
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .desk-cog:hover { background: var(--raised); color: var(--ink); }
  .desk-cog svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
  .desk-facts { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 22px; font-size: var(--t-ui); color: var(--quiet); }
  .desk-facts b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
  .desk-flag { color: var(--pine); font-weight: 600; }
  .desk-flag.off { color: var(--quiet); font-weight: 400; }

  .desk-panels { display: grid; gap: 14px; margin-bottom: 14px; }
  @media (min-width: 640px) { .desk-panels { grid-template-columns: 1fr 1fr; } }
  .desk-panel {
    display: flex; flex-direction: column; align-items: flex-start;
    background: var(--panel); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 20px;
  }
  .desk-copy {
    margin: 10px 0 16px; font-size: var(--t-body); line-height: 1.6; color: var(--say);
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
  }
  .desk-panel .card-action { margin-top: auto; }
  .desk-panel > .desk-flag { margin-top: auto; }

  .set-form { max-width: 640px; }

  /* ---------- settings sub-tabs ----------
     A rule the width of the pane, and the tab you are on drawn on it: a 2px
     ink underline that meets the rule rather than floating above it. */
  .stab { display: flex; gap: 24px; border-bottom: 1px solid var(--line); }
  .stab button {
    background: none; border: 0; border-bottom: 2px solid transparent;
    padding: 10px 2px; margin-bottom: -1px;
    font-size: var(--t-tab); font-weight: 600; color: var(--say);
    transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
  }
  .stab button:hover { color: var(--ink); }
  .stab button[aria-pressed="true"] { color: var(--ink); font-weight: 600; border-bottom-color: var(--ink); }
  /* Only the pane scrolls: the header and the tabs hold still, and the page
     itself does not move while you are in Settings. */
  .set-pane { padding-top: 22px; flex: 1 1 0; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }

  /* The title and the tabs hold their place while the pane scrolls under them.
     They sit directly under the header, which is sticky too, so the offset is
     the header's height. */
  .set-head {
    position: sticky; top: var(--head-h); z-index: 10;
    background: var(--desk); padding-top: 12px;
  }
  .set-head .read { padding: 12px 0 12px; }

  /* inputs hold focus clearly */
  .field input:focus, .field textarea:focus, .field select:focus,
  .bar input:focus, .bar select:focus { border-color: var(--ink); outline: none; }

  /* ---------- inbox count, money inputs, account card ---------- */
  .count { font-family: var(--sans); font-variant-numeric: tabular-nums; font-size: var(--t-title); color: var(--quiet); }
  .money-input { position: relative; }
  .money-input .cur { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--quiet); font-weight: 400; }
  .money-input input { padding-left: 30px; }
  .account-card { display: flex; align-items: center; gap: 14px; padding: 18px 20px; border: 1px solid var(--line); border-radius: var(--r-lg); margin-bottom: 18px; }
  /* The name field is half the width of the account card above it, so the card
     keeps its shape and the field reads as a field rather than a banner. */
  .account-form .field { max-width: 50%; }
  .account-out { margin-top: 24px; }
  .avatar.lg { width: 48px; height: 48px; font-size: var(--t-title); }
  .account-who { display: flex; flex-direction: column; gap: 2px; }
  .account-who b { font-size: var(--t-sub); font-weight: 600; }
  .account-who span { font-size: var(--t-ui); color: var(--quiet); }
  /* The account's people, in Settings under People. The email is the fact, its
     state the one other thing worth saying, and the row is a hairline apart.
     The plus is the pane's one primary action, so it is the one filled mark. */
  .people { max-width: 640px; }
  .people-head { display: flex; align-items: center; gap: 12px; }
  .people-search {
    flex: 1 1 auto; min-width: 0;
    background: var(--field-bg); border: 1px solid var(--field-line); border-radius: var(--r-field);
    padding: 0 14px; height: var(--control-h); font-size: var(--t-body);
    -webkit-appearance: none; appearance: none;
    transition: border-color var(--dur) var(--ease);
  }
  .people-search:hover { border-color: var(--field-line-hover); }
  .people-search:focus { border-color: var(--ink); outline: none; }
  .people-search::placeholder { color: var(--quiet); }
  .btn-add {
    flex: none; width: var(--control-h); height: var(--control-h);
    display: grid; place-items: center;
    background: var(--ink); border: 1px solid var(--ink); border-radius: var(--r-pill);
    color: var(--desk);
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
  }
  .btn-add:hover { background: var(--press); border-color: var(--press); }
  .btn-add svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
  .people-list { list-style: none; margin: 18px 0 0; padding: 0; }
  .person { display: flex; align-items: center; gap: 16px; padding: 14px 0; border-top: 1px solid var(--hair); }
  .person[hidden] { display: none; }
  .person:first-child { border-top: 0; }
  .person-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .person-email { font-size: var(--t-body); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .person-state { font-size: var(--t-meta); color: var(--pine); font-weight: 600; }
  .person-state.off { color: var(--quiet); font-weight: 400; }
  .person-out { margin-left: auto; display: flex; gap: 8px; align-items: center; justify-content: flex-end; flex-wrap: wrap; }
  .person-face {
    flex: none; width: 36px; height: 36px; border-radius: 50%;
    object-fit: cover; background: var(--raised); border: 1px solid var(--line);
  }
  .person-face.initial {
    display: grid; place-items: center;
    font-size: var(--t-ui); font-weight: 600; color: var(--ink);
  }
  .empty-note { margin: 22px 0 0; font-size: var(--t-body); color: var(--quiet); line-height: var(--lh-body); }

  /* ---------- header refinements ---------- */
  .badge {
    display: grid; place-items: center;
    width: 32px; height: 32px; border-radius: var(--r);
    background: var(--ink); color: var(--desk); flex: none;
  }
  .badge .lambda { height: 0.66em; width: auto; fill: currentColor; }
  .avatar {
    width: 32px; height: 32px; border-radius: 50%;
    background: var(--raised); color: var(--ink);
    border: 1px solid var(--line);
    font-size: var(--t-ui); font-weight: 600;
    display: grid; place-items: center;
  }
  .avatar:hover { border-color: var(--field-line-hover); }

  /* ---------- the desk switcher ----------
     The desk you are on, and a menu of the rest. It lives beside you in the
     header, so switching is one click away rather than a trip through
     Settings. The chevrons point up and down because the menu can go either
     way, and the current desk wears a tick. */
  .desk-switch { position: relative; min-width: 0; }
  .desk {
    display: inline-flex; align-items: center; gap: 6px; max-width: 240px; min-width: 0;
    background: none; border: 1px solid var(--field-line); border-radius: var(--r-field);
    padding: 0 12px; height: var(--control-sm);
    font-size: var(--t-tab); font-weight: 600; color: var(--say);
    transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
  }
  .desk:hover, .desk[aria-expanded="true"] { color: var(--ink); border-color: var(--field-line-hover); }
  .desk-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .desk svg { width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

  .desk-menu {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 40;
    min-width: 252px; max-width: min(320px, calc(100vw - 32px));
    padding: 6px;
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg);
    box-shadow: var(--shadow-menu);
  }
  .desk-menu[hidden] { display: none; }
  .desk-item {
    display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
    background: none; border: 0; border-radius: var(--r);
    padding: 6px 10px; min-height: 38px;
    transition: background var(--dur) var(--ease);
  }
  .desk-item:hover { background: var(--raised); }
  .desk-item b { flex: 1; min-width: 0; font-size: var(--t-body); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .desk-item span { flex: none; font-size: var(--t-meta); color: var(--quiet); }
  .desk-item svg { width: 16px; height: 16px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
  .desk-item svg.desk-tick { stroke: var(--ink); stroke-width: 1.8; }
  .desk-menu-sep { height: 1px; background: var(--hair); margin: 6px 4px; }
  .desk-new { color: var(--say); }

  /* ---------- a page title ---------- */
  .page-title { margin: 0; font-family: var(--display); font-weight: 400; font-size: var(--t-page); line-height: var(--lh-hero); letter-spacing: var(--ls-hero); }

  @media (max-width: 520px) {
    :root { --gutter: 16px; }
    /* the add form arrives as a sheet from the bottom, where the thumb is */
    .modal { width: 100%; max-width: none; max-height: 92vh; margin: auto 0 0; border-radius: var(--r-lg) var(--r-lg) 0 0; border-bottom: 0; }
    @keyframes pop { from { opacity: 0; transform: translateY(24px); } }
    /* The word is the first thing that can go. The mark says the same thing
       in a fifth of the room, which is the whole point of having one. */
    .mark .word { display: none; }
    .read { padding: 30px 0 24px; }
    /* Five tiles over two rows sit better in halves than in thirds, which left
       the last row two thirds full and visibly ragged. */
    .figures { grid-template-columns: 1fr 1fr; }
    .figures div:nth-child(3) { grid-column: 1 / -1; }
    .grid2 { grid-template-columns: 1fr; }
    .s-head { gap: 14px; }
    .s-score b { font-size: var(--t-title); }
    /* Search takes its own line, so the selects after it wrap instead of
       running off the edge. */
    .bar input[type="search"] { flex-basis: 100%; }
    /* The header has five things to fit and no room: the switcher keeps its
       chevrons and drops the name it is already showing on the menu. */
    .topbar-inner { gap: 10px; }
    .topnav { gap: 0; }
    .desk { padding: 6px; }
    .desk-name { display: none; }
    .account-form .field { max-width: 100%; }
  }
  @media (prefers-reduced-motion: reduce) {
    * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  }
