/* Labels, tags, toasts, dialogs, tables — used across pages. */

* { box-sizing: border-box; }
  #page-actions { display: flex; gap: 8px; }
  #page-actions:not(:empty) { padding-right: 12px; margin-right: 4px; border-right: 1px solid var(--line); }
  /* the bar's title sits hard left; the cards themselves centre in the space beside the sidebar */
  .content { padding: 26px 26px 60px; display: grid; gap: 20px; align-content: start; max-width: 1040px; width: 100%; margin-inline: auto; }
  /* an empty page has nothing to align to, so its card centres in the whole space */
  .content.wide { max-width: none; }
  .bar { display: flex; align-items: center; gap: 14px; padding: 13px 0; flex-wrap: wrap; }
  .pill.hot { color: #fff; background: var(--accent-btn); border-color: var(--accent-btn); }
  /* A pill inside a heading was sitting on the text baseline, so against a 28px heading it hung
     below the letters rather than beside them. Centred on the heading instead, and sized to it. */
  h1 .pill, h2 .pill, h3 .pill { vertical-align: middle; position: relative; top: -0.12em; }
  .card-head h2 { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
  .card-head h2 .pill { top: 0; }
  .meter { height: 7px; border-radius: 99px; background: var(--line-soft); overflow: hidden; }
  .meter i { display: block; height: 100%; background: var(--accent); }
  .keybox { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
  .months { display: flex; gap: 3px; margin-top: 2px; }
  .months i { height: 8px; flex: 1; border-radius: 2px; background: var(--line-soft); position: relative; }
  .chips { display: flex; flex-wrap: wrap; gap: 5px; }
  .page-intro { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
  .page-intro .sub { max-width: 68ch; }
  /* template form */
  .form-section { border-bottom: 1px solid var(--line-soft); padding: 18px 20px; display: grid; gap: 14px; }
  .form-section:last-of-type { border-bottom: 0; }
  .form-section > header { display: grid; gap: 3px; padding-bottom: 2px; border-bottom: 1px solid var(--line-soft); }
  .form-section h3 { font-size: 15px; }
  .form-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 12px 16px; }
  .form-grid .wide { grid-column: 1 / -1; }
  /* repeated rows: watermarks, image layers */
  .rows { display: grid; gap: 8px; }
  .cell { display: grid; gap: 4px; flex: 1 1 148px; min-width: 0; }
  .cell.narrow { flex: 0 1 78px; }
  .cell.mid { flex: 0 1 132px; }
  .cell input, .cell select { padding: 7px 9px; font-size: 13px; }
  .coming { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; padding: 12px 14px; border: 1px dashed var(--line); border-radius: 6px; color: var(--muted); font-size: 13.5px; }
  .week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; }
  .slot { font: inherit; font-family: var(--mono); font-size: 12px; padding: 5px 7px; border-radius: 4px; border: 1px solid var(--line); background: var(--raised); color: var(--ink); cursor: pointer; }
  .type-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px; }
  .type-tile { display: grid; gap: 4px; text-align: left; padding: 12px 13px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface); color: var(--ink); font: inherit; cursor: pointer; }
  .type-tile b { font-size: 14.5px; display: flex; align-items: center; gap: 7px; }
  .form-foot { display: flex; gap: 10px; justify-content: space-between; align-items: center; padding: 16px 20px; border-top: 1px solid var(--line-soft); background: var(--surface); flex-wrap: wrap; }
  .crumb { background: transparent; border: 0; color: var(--accent); font: inherit; font-size: 13px; cursor: pointer; padding: 0; }
  /* Standing on its own above the first card rather than inside one. justify-self, because a
     grid blockifies its items: a button left to stretch the column centres its own label, which
     is why this read as a centred crumb over a left-aligned page. */
  .crumb:not(.inline) { justify-self: start; margin: 0 0 12px; }
  .crumb:hover { text-decoration: underline; }
  /* empty states */
  /* header stays at the top; only the empty card centres in what's left */
  #app.only-empty { min-height: calc(100vh - 170px); grid-template-rows: auto minmax(0, 1fr); }
  #app.only-empty .empty-card { align-self: center; justify-self: center; }
  /* views return several cards; they stack with the same rhythm as the page */
  #app { display: grid; gap: 20px; align-content: start; }
  .toast { position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%); background: var(--ink); color: var(--ground); padding: 10px 16px; border-radius: 6px; font-size: 14px; box-shadow: var(--shadow); z-index: 60; }
  .signin { max-width: 420px; margin: 60px auto; display: grid; gap: 16px; text-align: center; }
  .signin form { display: grid; gap: 10px; }
  .signin h1 { margin-bottom: 2px; }

  /* Google's button is theirs, not ours: white, their mark, their wording */
  .btn.google { background: #FFFFFF; color: #1F1F1F; border: 1px solid #DADCE0; font-weight: 500;
                display: flex; align-items: center; justify-content: center; gap: 11px; }
  .btn.google:hover { background: #F7F8F8; }

  /* the "or" rule between the two ways in */
  .or { display: flex; align-items: center; gap: 12px; color: var(--muted); font-size: 12.5px;
        font-family: var(--mono); letter-spacing: .08em; text-transform: uppercase; margin: 2px 0; }
  .or::before, .or::after { content: ""; flex: 1; height: 1px; background: var(--line); }

  /* the code itself: spaced out, so a six-digit string reads as six digits */
  input.code { font-family: var(--mono); font-size: 26px; letter-spacing: .3em; text-align: center; }

  /* setup asks three questions, left-aligned — a form is not a landing page */
  /* .signin form sets gap: 10px and outranks a bare .setup, so this has to match its weight */
  .signin form.setup { text-align: left; gap: 18px; }
  .setup .btn { margin-top: 10px; }             /* let the last field finish before the action */
  .setup .field { display: grid; gap: 6px; }
  .setup .field > span { font-size: 13.5px; font-weight: 600; }
  .setup .field em { font-style: normal; font-size: 12px; color: var(--muted); line-height: 1.45; }
  .visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden;
                     clip: rect(0 0 0 0); white-space: nowrap; }
  .hidden { display: none !important; }
  table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
  th, td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--line-soft); }

  /* ---------- top bar controls ---------- */
  .search-open {
    display: flex; align-items: center; gap: 9px; padding: 7px 10px 7px 11px;
    border: 1px solid var(--line); border-radius: 8px; background: var(--raised);
    color: var(--muted); font: inherit; font-size: 13.5px; cursor: pointer; min-width: 190px;
  }
  .search-open:hover { border-color: var(--muted); color: var(--ink); }
  .search-open svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.7;
                     stroke-linecap: round; }
  .search-open span { margin-right: auto; }
  .search-open kbd { font-family: var(--mono); font-size: 10.5px; padding: 2px 5px; border-radius: 4px;
                     border: 1px solid var(--line); color: var(--muted); }

  .icon-btn { position: relative; display: grid; place-items: center; width: 34px; height: 34px;
              border: 1px solid transparent; border-radius: 8px; background: transparent;
              color: var(--muted); cursor: pointer; }
  .icon-btn:hover { color: var(--ink); background: var(--raised); border-color: var(--line); }
  .icon-btn svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 1.6;
                  stroke-linecap: round; stroke-linejoin: round; }
  .icon-btn .dot { position: absolute; top: 7px; right: 8px; width: 7px; height: 7px;
                   border-radius: 99px; background: var(--accent); border: 2px solid var(--surface); }

  button.avatar { border: 0; cursor: pointer; font: inherit; }

  /* ---------- popovers hung off the top bar ---------- */
  /* min-width alone pushed it off a narrow screen: it is positioned from the right, so a
     width the viewport cannot hold spills past the left edge. */
  .pop { position: fixed; z-index: 60; min-width: min(250px, calc(100vw - 24px));
         max-width: min(340px, calc(100vw - 24px)); padding: 6px;
         background: var(--raised); border: 1px solid var(--line); border-radius: 10px;
         box-shadow: 0 18px 44px rgba(0, 0, 0, .45); display: grid; gap: 2px; }
  .pop button { display: grid; gap: 2px; text-align: left; width: 100%; padding: 9px 10px;
                border: 0; border-radius: 7px; background: transparent; color: var(--ink);
                font: inherit; font-size: 14px; cursor: pointer; }
  .pop button:hover, .pop button.on { background: var(--surface); }
  .pop button em { font-style: normal; font-size: 12px; color: var(--muted); line-height: 1.4; }
  .pop button.bad span { color: var(--accent); }
  .pop-empty { padding: 14px 10px; font-size: 13px; color: var(--muted); }
  .pop-head { padding: 9px 10px; display: grid; gap: 1px; border-bottom: 1px solid var(--line-soft);
              margin-bottom: 2px; }
  .pop-head b { font-size: 13.5px; }
  .pop-head span { font-size: 12px; color: var(--muted); }
  .pop-search { width: 340px; }
  .pop-search input { width: 100%; margin-bottom: 4px; }
  /* the kind of thing sits beside the name, not under it — float has no effect in a grid */
  .pop-search button { grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; }
  .pop-search button span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .pop-search button em { font-family: var(--mono); font-size: 10.5px;
                          letter-spacing: .06em; text-transform: uppercase; }
  .pop-label { padding: 8px 10px 3px; font-family: var(--mono); font-size: 9.5px;
               letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
  .pop-rule { height: 1px; background: var(--line-soft); margin: 4px 0; }
  .pop button.on span { color: var(--accent); }
  .not-sold { font-size: 12.5px; color: var(--muted); font-family: var(--mono);
              letter-spacing: .02em; white-space: nowrap; }
  /* an even inset: with no bottom margin it sat flush against the card's lower edge
     whenever it was the only thing in one. */
  .notice { margin: 14px 16px; padding: 12px 14px; display: grid; gap: 4px;
            border: 1px solid var(--accent); border-left-width: 3px; border-radius: 6px;
            background: var(--surface); }
  .notice b { font-size: 13.5px; }
  .notice span { font-size: 13px; color: var(--muted); line-height: 1.45; }

  /* ---------- what this licence doesn't include ----------
   *
   * Shown rather than hidden: a reader who can't see the Scheduler at all has no idea the product
   * schedules. Dimmed, with the reason on hover, it advertises itself honestly.
   */
  .side-nav button.nav-locked { opacity: .45; }
  .side-nav button.nav-locked svg { opacity: .5; }
  .side-nav button.nav-locked::after {
    content: ""; width: 9px; height: 11px; margin-left: auto; flex: none;
    border: 1.4px solid currentColor; border-radius: 2px; border-top-width: 5px;
    border-top-color: transparent; box-shadow: inset 0 -1.4px 0 transparent;
  }
  body:not(.nav-open) .side-nav button.nav-locked::after { display: none; }

  .card.locked { display: grid; justify-items: center; text-align: center; gap: 10px;
                 padding: 44px 28px 40px; }
  .locked-mark { width: 30px; height: 30px; stroke: var(--accent); fill: none; stroke-width: 1.5;
                 stroke-linecap: round; stroke-linejoin: round; opacity: .9; }
  .card.locked h2 { font-size: 19px; }
  .card.locked p { color: var(--muted); font-size: 14.5px; max-width: 46ch; line-height: 1.6; }
  .card.locked .btns { margin-top: 6px; }

  /* not built yet: a version, not a padlock — nothing is being withheld */
  .side-nav button.nav-coming::after {
    content: attr(data-coming); width: auto; height: auto; border: 0; border-radius: 0;
    font-family: var(--mono); font-size: 9.5px; letter-spacing: .06em; color: var(--muted);
    box-shadow: none;
  }
  .card.locked.coming .locked-mark { display: none; }
  .coming-tag { font-family: var(--mono); font-size: 10px; letter-spacing: .12em;
                text-transform: uppercase; color: var(--accent);
                border: 1px solid var(--accent); border-radius: 3px; padding: 3px 8px; }

  /* choosing how many seats to add, beside the button that buys them */
  .seat-add { display: inline-flex; align-items: center; gap: 4px; }
  .seat-add b { min-width: 22px; text-align: center; font-family: var(--mono); font-size: 13px; }
  .seat-add .icon-only { padding: 6px 9px; line-height: 1; font-size: 14px; }

  /* ---------- while the first screen is being fetched ----------
   *
   * Three round trips stand between opening the dashboard and knowing what to draw. A dark
   * rectangle for that long reads as a page that has failed, so the shape of the answer is drawn
   * first: a heading, two cards, the rail. Nothing here claims to be data — no numbers, no names.
   */
  /* Two classes, so this still wins inside the mobile block where `.side-nav` is given a
     display of its own — a single class there would leave the skeleton on screen for good. */
  #boot, .side-nav.sk-nav, .side-tools.sk-nav { display: none; }
  body.booting #boot { display: grid; gap: 20px; }
  /* The rail's own rules give these their size and spacing; all that is added here is the grey.
     The labels are empty spans carrying only a width, so the shape of each word survives. */
  body.booting .side-nav.sk-nav { display: grid; }
  body.booting .side-tools.sk-nav { display: grid; }
  .sk-nav { pointer-events: none; }
  .sk-nav button { cursor: default; }
  /* A label's height comes from its text, so these carry text too — invisible, with the grey bar
     drawn over it. Fixing a height instead left every row short and the rail crept upwards. */
  .sk-nav button > span, .sk-nav .side-group span {
    opacity: 1 !important; transform: none !important;
    position: relative; color: transparent; background: none; animation: none;
  }
  .sk-nav button > span::after, .sk-nav .side-group span::after {
    content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
    width: 100%; height: 10px; border-radius: 4px;
    background: linear-gradient(90deg, var(--raised) 0%, var(--line) 50%, var(--raised) 100%);
    background-size: 220% 100%; animation: sk-slide 1.4s ease-in-out infinite;
  }
  /* a heading is quieter and shorter than the rows under it, or the four groups read as one list */
  .sk-nav .side-group span::after { height: 7px; opacity: .55; }
  .sk-nav .side-group::before { opacity: 0; }
  .sk-ic { width: 18px; height: 18px; border-radius: 5px; flex: none; opacity: .8; }

  /* The standing-in page. #boot carried its own gap, so the copy that loadTab puts inside #app
     had none at all and its pieces sat flush against each other. The gap is #app's own, and the
     card is the real card's geometry — same radius, same ground, same shadow — because the
     skeleton is swapped for cards in place and anything else makes the swap a jump. */
  .sk { display: grid; gap: 20px; }
  .sk-head { display: grid; gap: 9px; padding-bottom: 2px; }
  .sk-card { display: grid; gap: 12px; border: 1px solid var(--line); border-radius: 6px;
             background: var(--raised); box-shadow: var(--shadow); padding: 18px 20px 22px; }
  /* Paint only — no height. Each shape sets its own, and a shared height here silently overrode
     them by sitting later in the file. */
  .sk-line, .sk-ic {
    border-radius: 4px; display: block;
    background: linear-gradient(90deg, var(--raised) 0%, var(--line) 50%, var(--raised) 100%);
    background-size: 220% 100%; animation: sk-slide 1.4s ease-in-out infinite;
  }
  .sk-line { height: 11px; }
  .sk-line.lg { height: 22px; width: 42%; }
  .sk-line.sm { height: 10px; width: 62%; }
  .sk-line.md { height: 15px; width: 30%; }
  .sk-line.sh { width: 72%; }
  @keyframes sk-slide { from { background-position: 120% 0; } to { background-position: -20% 0; } }
  @media (prefers-reduced-motion: reduce) {
    .sk-line, .sk-ic { animation: none; background: var(--raised); }
    .sk-nav span::after { animation: none; background: var(--raised); }
  }

  /* the seat control sits under the seat count, which is where someone looking to add one looks */
  .seat-add { display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
              margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line-soft); }
  .seat-add-label { flex-basis: 100%; font-size: 12.5px; color: var(--muted); margin-bottom: 2px; }

  /* the tier you already hold, stated rather than sold */
  .tier-held { font-family: var(--mono); font-size: 11px; letter-spacing: .06em;
               text-transform: uppercase; color: var(--muted); padding: 7px 0; }

  /* An offer that has to explain itself before it asks for money, so the button comes last —
     after what it is, what it does and what it costs, where the reader ends up. */
  .row-offer { display: block; }
  /* the offer's action closes the block, on the right where the eye leaves the line */
  .offer-go { margin-top: 14px; justify-content: flex-end; }
  .row-list { margin: 8px 0 10px; padding-left: 18px; display: grid; gap: 5px;
              color: var(--muted); font-size: 13.5px; line-height: 1.5; }
  .row-list li::marker { color: var(--accent); }

  /* the ledger: dates and figures line up, so the eye can run down a column */
  .ledger { width: 100%; border-collapse: collapse; font-size: 14px; }
  .ledger th { text-align: left; font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
               text-transform: uppercase; color: var(--muted); font-weight: 400;
               padding: 0 16px 11px; }
  /* A row is scanned, not read: it wants enough height that the eye can track across it without
     the line above and below crowding in. 11px of padding on 14px text left barely a third of a
     line between rows. */
  .ledger td { padding: 14px 16px; border-top: 1px solid var(--line-soft); line-height: 1.45; }
  .ledger .num { text-align: right; font-variant-numeric: tabular-nums; }
  /* Seat controls sit beside the figure and stay out of the way until the row is under the
     pointer: a table of numbers should read as numbers, not as a row of buttons. */
  .seat-nudge { display: inline-flex; gap: 2px; margin-left: 8px; opacity: 0; transition: opacity .12s; }
  .ledger tr:hover .seat-nudge, .seat-nudge:focus-within { opacity: 1; }
  .seat-nudge .linkish { font-family: var(--mono); font-size: 13px; line-height: 1;
                         padding: 2px 5px; border: 1px solid var(--line); border-radius: 3px; }
  /* a figure's unit belongs on the figure's line, not broken across three of them */
  .ledger .num .row-meta { white-space: nowrap; }
  .ledger .right { text-align: right; width: 1%; white-space: nowrap; }
  /* A date is as wide as a date. Left to itself a table shares the width out evenly and pushes
     two date columns across half of it, stranding the names and emails that need the room. */
  .ledger .tight { width: 1%; white-space: nowrap; text-align: right; }
  .ledger th.tight .sorter { justify-content: flex-end; }
  /* an address is not a date: it takes the width it needs up to a point, then trails off, rather
     than either pushing the last column off the table or collapsing to a single letter */
  .ellip { display: inline-block; max-width: 170px; overflow: hidden; text-overflow: ellipsis;
           white-space: nowrap; vertical-align: bottom; }
  .ledger tr.refunded td { color: var(--muted); }
  /* a row that opens something: the whole row, because that is what the eye and the thumb aim at */
  .ledger tr.opens { cursor: pointer; }
  .ledger tr.opens:hover td { background: var(--surface); }
  .row.opens { cursor: pointer; }
  .row.opens:hover { background: var(--surface); }
  /* the row is the target, so it has to show focus; the buttons inside keep their own */
  .row.opens:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
  .ledger tr.opens:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
  .ledger tr.opens:hover td:first-child b { color: var(--accent); }

  /* on or off, told at a glance rather than inferred from what is missing */
  /* the action sits with the heading, top right, while the explanation runs underneath */
  .card.conn .card-head { align-items: start; gap: 16px; }
  .card.conn .card-head .btns { flex: none; }
  .card.conn h2::before { content: ""; display: inline-block; width: 8px; height: 8px;
                          border-radius: 50%; margin-right: 9px; vertical-align: middle; }
  .card.conn-on h2::before { background: var(--good); }
  .card.conn-off h2::before { background: var(--line); }

  .conn-body { padding: 0 16px 18px; display: grid; gap: 4px; }
  .conn-body .row-list { margin-top: 0; }

  /* settings: a field says where its value came from, only when that is somewhere else */
  .field-note { font-style: normal; font-size: 12px; color: var(--muted); line-height: 1.4; }
  .lock-switch { display: inline-flex; align-items: center; gap: 8px; font-size: 13px;
                 color: var(--muted); }

  /* ---------- a small either/or, for choosing who a setting applies to ----------
   *
   * Borrowed by name from the site, which had the styles; here it had none and fell back to raw
   * browser buttons. One track, the chosen segment lifted rather than coloured in, so it reads as
   * a switch instead of three things to click.
   */
  .segctl { display: inline-flex; padding: 2px; gap: 2px; border: 1px solid var(--line);
            border-radius: 7px; background: var(--ground); }
  .segctl button { font: inherit; font-size: 12.5px; line-height: 1; padding: 7px 12px;
                   border: 0; border-radius: 5px; background: transparent; color: var(--muted);
                   cursor: pointer; white-space: nowrap;
                   transition: background .12s ease, color .12s ease; }
  .segctl button:hover { color: var(--ink); }
  .segctl button[aria-pressed="true"] { background: var(--surface); color: var(--ink);
                                        font-weight: 600; box-shadow: var(--shadow); }

  /* a provider reads as a row with a state, not as two anonymous inputs */
  .form-section.provider > header { display: flex; align-items: baseline; gap: 10px;
                                    flex-wrap: wrap; }
  .provider-state { font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
                    text-transform: uppercase; color: var(--muted);
                    border: 1px solid var(--line); border-radius: 3px; padding: 3px 7px; }
  .provider-state.on { color: var(--good); border-color: var(--good); }
  .provider-link { margin-left: auto; font-size: 12px; color: var(--muted);
                   text-decoration: none; }
  .provider-link:hover { color: var(--accent); }

  /* the chooser that brings a provider onto the page */
  .add-provider { background: var(--ground); }
  .add-provider .field { max-width: 320px; }

  /* the phone's menu button and the veil behind its drawer */
  .nav-toggle { display: none; width: 38px; height: 34px; margin-right: 4px; flex: none;
                border: 1px solid var(--line); border-radius: 6px; background: transparent;
                cursor: pointer; padding: 9px 9px; gap: 4px;
                flex-direction: column; justify-content: center; }
  .nav-toggle span { display: block; height: 1.5px; background: var(--ink); border-radius: 2px;
                     transition: transform .2s ease, opacity .2s ease; }
  .nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
  .nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }
  .nav-veil { display: none; position: fixed; inset: 0; height: 100dvh;
              background: rgba(0, 0, 0, .5); z-index: 85; }

  #theme-toggle svg { width: 17px; height: 17px; stroke: currentColor; fill: none;
                      stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

  /* the service's own numbers, at a glance */
  .tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
           gap: 1px; background: var(--line-soft); border-block: 1px solid var(--line-soft); }
  /* eight figures read as two rows of four, not seven and a lonely one */
  .tiles.of4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .tile { background: var(--surface); padding: 16px 18px; display: grid; gap: 3px; }
  .tile b { font-family: var(--display); font-size: 26px; font-weight: 800; letter-spacing: -.02em;
            font-variant-numeric: tabular-nums; }
  .tile span { font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
               text-transform: uppercase; color: var(--muted); }
  /* A "tight" column shrinks to its content, which for a select is nothing at all. */
  [data-request-status] { min-width: 124px; }

  /* Text inside a row that opens something, so it looks like it will. */
  .link { color: var(--accent); cursor: pointer; }
  .link:hover { text-decoration: underline; }

  /* Label over value, for detail that is words rather than figures. */
  .trial-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
                 gap: 16px 24px; }
  .trial-facts > div { display: grid; gap: 3px; min-width: 0; }
  .trial-facts span { font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
                      text-transform: uppercase; color: var(--muted); }
  .trial-facts b { font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
  .tile.quiet { background: transparent; padding: 0; }
  .tile.quiet b { font-size: 19px; }

  /* an id that can be copied, styled as the link it behaves like */
  .linkish { font: inherit; font-family: var(--mono); font-size: 11px; color: var(--muted);
             background: none; border: 0; padding: 0; cursor: pointer; text-align: left; }
  .linkish:hover { color: var(--accent); text-decoration: underline; }

  /* ---------- a list you can question: search, slice, order, page ----------
   *
   * The controls sit between the heading and the rows, in the order the questions are asked: what
   * are you looking for, which ones, how many at a time — and then, on the right, what you are
   * actually looking at, because a count with no position in it ("1,204 people") tells you nothing
   * about the twenty-five on the screen.
   */
  .listbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
             padding: 12px 20px; border-bottom: 1px solid var(--line-soft);
             background: var(--surface); }
  .listbar select { width: auto; min-width: 160px; font-size: 13px; padding: 7px 9px;
                    background: var(--raised); }

  /* the search box carries its own glass, so it reads as a search rather than a text field */
  .finder { position: relative; flex: 1 1 240px; min-width: 180px; display: flex; }
  .finder input { padding-left: 33px; padding-right: 30px; background: var(--raised); }
  .finder > svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
                  width: 14px; height: 14px; stroke: var(--muted); fill: none; stroke-width: 1.7;
                  stroke-linecap: round; pointer-events: none; }
  .finder .clear { position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
                   width: 22px; height: 22px; border: 0; border-radius: 4px; background: none;
                   color: var(--muted); font-size: 17px; line-height: 1; cursor: pointer; }
  .finder .clear:hover { color: var(--ink); background: var(--surface); }

  /* a heading that sorts looks like a heading until you point at it */
  .ledger th .sorter { font: inherit; color: inherit; letter-spacing: inherit;
                       text-transform: inherit; background: none; border: 0; padding: 0;
                       cursor: pointer; display: inline-flex; align-items: baseline; gap: 4px; }
  .ledger th .sorter:hover { color: var(--ink); }
  .ledger th .sorter.on { color: var(--ink); }
  .ledger th .sorter em { font-style: normal; color: var(--accent); }
  .ledger .num .sorter { justify-content: flex-end; }

  /* ---------- the pager ----------
   *
   * The pages themselves, not a sentence about them: you can see how many there are, how far in
   * you are, and go to any of them. Prev and Next hold the ends so the numbers stay put as you
   * move, rather than sliding under the pointer.
   */
  .listfoot { display: flex; align-items: center; justify-content: space-between; gap: 12px;
              flex-wrap: wrap; padding: 10px 20px; border-top: 1px solid var(--line-soft); }
  .listfoot > .sub { font-size: 13px; }
  .pager { display: flex; align-items: center; gap: 12px; margin-left: auto; }
  .page-nums { display: flex; align-items: center; gap: 2px; flex-wrap: wrap;
               justify-content: center; }
  .page-step, .page-num {
    font: inherit; font-size: 13px; font-weight: 500; color: var(--muted); cursor: pointer;
    background: transparent; border: 1px solid transparent; border-radius: 5px;
    padding: 6px 10px; white-space: nowrap; }
  .page-num { min-width: 32px; text-align: center; font-variant-numeric: tabular-nums;
              padding: 6px 8px; }
  .page-step:hover, .page-num:hover { color: var(--ink); background: var(--surface); }
  .page-num.on, .page-num.on:hover { color: var(--ink); font-weight: 600;
                                     border-color: var(--line); background: var(--surface); }
  .page-step:disabled { color: var(--line); cursor: default; }
  .page-step:disabled:hover { background: transparent; color: var(--line); }
  .page-gap { color: var(--muted); padding: 0 4px; user-select: none; }

  .btn.ghost { background: transparent; font-weight: 500; }
  .btn.ghost:disabled { color: var(--muted); border-color: var(--line-soft); cursor: default; }
  .btn.ghost:disabled:hover { border-color: var(--line-soft); }

  /* ---------- tabs inside a card ----------
   *
   * An account's licences, its machines and its history are three answers to three different
   * questions. Stacked they are a page you scroll past; as tabs, the one you came for is the one
   * you see, and the counts say what is behind the other two before you open them.
   */
  .card-head.tabbed { display: grid; gap: 8px; padding-bottom: 0; align-items: start; }
  .card-head.tabbed .sub { padding-bottom: 14px; }
  /* two parts, because `.card-head > div` is two and would otherwise lay these out as a column */
  .card-head .tabs { display: flex; gap: 2px; flex-wrap: wrap; margin-bottom: -1px; }
  .tabs button { font: inherit; font-size: 14px; font-weight: 600; color: var(--muted);
                 background: transparent; border: 0; border-bottom: 2px solid transparent;
                 padding: 4px 12px 10px; cursor: pointer; display: inline-flex;
                 align-items: baseline; gap: 7px; }
  .tabs button:hover { color: var(--ink); }
  .tabs button[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--accent); }
  .tabs em { font-style: normal; font-family: var(--mono); font-size: 11px; color: var(--muted);
             background: var(--surface); border-radius: 99px; padding: 2px 7px;
             font-variant-numeric: tabular-nums; }
  .tabs button[aria-selected="true"] em { color: var(--ink); }
  /* A wide table scrolls on its own rather than pushing the page sideways. It can only do that
     inside boxes that are allowed to be narrower than their contents — a grid item's default
     min-width is its content, so without this the card grows and the whole page scrolls instead. */
  .scroller { overflow-x: auto; min-width: 0; }
  .card, .card > * { min-width: 0; }

  /* ---------- what people are using ----------
   *
   * A bar for how much and a number for how many accounts, because they answer different
   * questions and the second one is the one that matters: reach, not volume.
   */
  .usage { display: grid; gap: 1px; background: var(--line-soft);
           border-bottom: 1px solid var(--line-soft); }
  /* fixed tracks rather than fractions: these rows read as a table, and a column that resolves to
     a different width on every row because its label is longer is a table with a wobble in it */
  .use { background: var(--raised); padding: 12px 20px; display: grid; align-items: center;
         gap: 4px 14px;
         grid-template-columns: minmax(0, 190px) minmax(60px, 1fr) 84px 104px 124px; }
  .use b { font-weight: 600; font-size: 14px; }
  .use-bar { height: 6px; border-radius: 99px; background: var(--surface);
             border: 1px solid var(--line-soft); overflow: hidden; }
  .use-bar i { display: block; height: 100%; background: var(--accent); }
  .use-n { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 14px;
           text-align: right; white-space: nowrap; }
  .use-who, .use-month { font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em;
                         text-transform: uppercase; color: var(--muted); text-align: right;
                         white-space: nowrap; }
  /* one account's own figures: no bar to compare against, so the name and the number are enough */
  .usage.compact .use { grid-template-columns: 1fr auto; }
  /* a feature at zero stays on the page and steps back, rather than being described underneath */
  .use.off { color: var(--muted); }
  .use.off .use-n { font-weight: 400; }
  .use.off .use-bar { opacity: .5; }

  /* A licence in a cell, and an organisation with its role beside it. One weight for the thing,
     one for the detail, and no borders: a table of bordered tags reads as a table of buttons. */
  .stack { display: grid; gap: 4px; }
  .named, .held { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
  .named em, .held em { font-style: normal; font-size: 12.5px; color: var(--muted); }
  .held.gone { color: var(--muted); }
  .none { font-size: 13.5px; color: var(--muted); }
  /* a quiet strip for something that introduces a table rather than filtering it */
  .listbar.quiet { background: transparent; }
  /* the same control at two weights: a name that is the row's subject, and one that is a
     reference from somewhere else. Neither should read as an id. */
  .linkish.strong { font-family: var(--body); font-size: 14.5px; font-weight: 600; color: var(--ink); }
  .linkish.plain { font-family: var(--body); font-size: 14px; color: var(--ink); }
  /* an account that is only someone's own is still a link, but it is not the news on the row */
  .linkish.plain.quiet { color: var(--muted); }
  .linkish.strong:hover, .linkish.plain:hover { color: var(--accent); }

  /* ---------- which stretch, and the shape of it ----------
   *
   * The control sits above the cards rather than inside one, because it governs all of them —
   * a chooser buried in a card looks like it only applies to that card.
   */
  .rangebar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
  .rangebar .dates { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
  .rangebar input[type="date"] { width: auto; font-size: 13px; padding: 7px 9px;
                                 background: var(--raised); }

  /* bars in CSS, not SVG: crisp at any width and themed by the same tokens as the rest */
  .chart { padding: 18px 20px 14px; border-bottom: 1px solid var(--line-soft); }
  .chart-plot { position: relative; padding-left: 58px; }
  .chart-bars { display: flex; align-items: flex-end; gap: 2px; height: 148px;
                border-bottom: 1px solid var(--line);
                background: linear-gradient(var(--line-soft) 1px, transparent 1px) top left / 100% 50%
                            no-repeat; }
  /* a day is a day: over a short window the bars stay narrow rather than stretching into slabs */
  .chart-bars .bar { flex: 1 1 0; min-width: 2px; max-width: 40px; height: 100%; display: flex;
                     align-items: flex-end; }
  .chart-bars .bar i { display: block; width: 100%; background: var(--accent); border-radius: 2px 2px 0 0;
                       transition: opacity .12s ease; }
  .chart-bars .bar:hover i { opacity: .75; }
  .chart-bars .bar.nil { align-items: flex-end; }
  .chart-bars .bar.nil::after { content: ""; display: block; width: 100%; height: 2px;
                                background: var(--line-soft); }
  .chart-max, .chart-mid, .chart-zero {
    position: absolute; left: 0; width: 52px; text-align: right;
    font-family: var(--mono); font-size: 10px; letter-spacing: .06em; color: var(--muted); }
  .chart-max { top: -4px; }
  .chart-mid { top: calc(50% - 8px); }
  .chart-zero { bottom: -6px; }
  .chart-axis { display: flex; justify-content: space-between; padding: 8px 0 0 58px;
                font-family: var(--mono); font-size: 10px; letter-spacing: .06em;
                text-transform: uppercase; color: var(--muted); }

  /* a proportion: one bar, and the numbers spelled out beside it */
  .splits { gap: 18px; }
  .split { display: grid; gap: 8px; }
  .split-bar { display: flex; height: 8px; border-radius: 99px; overflow: hidden;
               background: var(--surface); }
  .split-bar i { display: block; }
  .split-keys { display: flex; gap: 16px; flex-wrap: wrap; font-size: 13px; color: var(--muted); }
  .split-key { display: inline-flex; align-items: center; gap: 6px; }
  .split-key i { width: 9px; height: 9px; border-radius: 2px; }
  .split-key b { color: var(--ink); font-variant-numeric: tabular-nums; }
  /* four steps of the accent, so a split reads as one quantity divided rather than four things */
  .p0 { background: var(--accent); }
  .p1 { background: color-mix(in srgb, var(--accent) 58%, var(--surface)); }
  .p2 { background: color-mix(in srgb, var(--accent) 34%, var(--surface)); }
  .p3 { background: color-mix(in srgb, var(--accent) 18%, var(--surface)); }

  /* The agreement on the setup form. A row, not a block: the tick and the sentence belong to each
     other, and the tick keeps its own line when the sentence wraps. */
  .agree { display: flex; align-items: flex-start; gap: 10px; margin: 2px 0 4px;
           font-size: 13.5px; line-height: 1.5; color: var(--muted); cursor: pointer; }
  /* Every input in here is width:100% by default, which a tick box has no business being — it
     stretched the full row and squeezed the sentence into a column one word wide. `flex: none`
     does not undo it: nothing was shrinking it, it was asking to be that size. So it is given one,
     the same way `.switch input` is. */
  .agree input[type="checkbox"] { width: 16px; height: 16px; flex: none; padding: 0;
                                  margin: 2px 0 0; accent-color: var(--accent); }
  .agree > span { flex: 1; min-width: 0; }
  .agree a { color: var(--accent); }
