/* Direct Connect console, page-specific layout.
 * ===========================================================================
 *
 * WHAT THIS IS. Every rule that used to sit in the inline <style> block of
 * static/index.html, moved out byte for byte by DC-90. Nothing was rewritten,
 * merged, reordered or renamed. The file it came from is the whole signed-in
 * console and it was 12,564 lines; this took 1,511 of them out.
 *
 * WHY IT IS NOT THE WHOLE BLOCK. The @import for the two Google fonts is still
 * inline in index.html, deliberately, and it is the one thing that could not
 * come with the rest.
 *
 * An @import inside an inline <style> starts fetching the moment the HTML
 * parser reaches it. An @import inside THIS file cannot start until this file
 * has itself been fetched and parsed, which puts two round trips in series
 * before a single glyph is available. That is a real change to what a person
 * sees on a slow connection, and this card is a move rather than a rewrite. So
 * the @import stays where it is, above the link to this file, and the fetch
 * order is exactly what it was.
 *
 * WHERE IT SITS IN THE CASCADE, AND WHY THE LINK IS WHERE IT IS. The order in
 * the head is tokens.css, shell.css, the inline @import, then this file. That
 * is the same order the rules were in before: the @import was the first thing
 * in the block and these rules followed it. Later wins in CSS, so moving this
 * file above the @import would be a silent change to which rule applies. It is
 * below it, exactly as it was.
 *
 * ?v=1 AND WHY IT IS NOT ?v=2 LIKE THE OTHER TWO. tokens.css and shell.css are
 * at v=2 because their v=1 is the unversioned URL every deployed page asked for
 * before the buster existed, so their first real version had to be 2. This file
 * has no such history: nobody anywhere holds a copy of console.css under any
 * URL, so its first version is 1. Same reasoning as shared.js, which is at v=1
 * for the same reason and not by coincidence.
 *
 * BUMP IT IN THE SAME CHANGE AS THE CONTENTS. netlify.toml serves this at
 * max-age=3600 with stale-while-revalidate=86400 on a filename that carries no
 * content hash, so without a bump a reader can keep serving an hour-old copy of
 * this file to new markup. New markup meeting old rules is the one combination
 * that breaks a page silently, for exactly one person.
 * ===========================================================================
 */

/* Page-specific layout only. Colour, type and radius come from tokens.css,
   shared chrome (top bar, cards, tables, pills, charts) from shell.css. */
.login{max-width:420px;margin:8vh auto 0;padding:var(--s-4)}
/* THE SIGN IN CARD SIZES ITS OWN BUTTONS. Six of them carried a width and a
   top margin in a style attribute, at 14px and 6px, neither of which is a
   step and neither of which a media query can reach. Full width for the
   card's own action, auto for the quiet control that trails it. */
.login form>button,.login>button:not(.sm){width:100%}
.login form>button{margin-top:var(--s-3)}
.login>button.sm{margin-top:var(--s-2)}
.login h2,.errcard h2,.modal .mc h2{font-family:var(--display);color:var(--navy);font-size:var(--fs-title);font-weight:700;margin:0 0 var(--s-1);letter-spacing:var(--tr-tight)}
/* .cs moved to tokens.css and now shares the .factline rule. It was the same
   four properties minus the measure, which is how one rule came to have two
   names that disagreed. The header there says when the alias can go. */
/* The sentence under a page title. It was running to 97 characters a line,
   which is half again the comfortable measure and reads as a wall. */
/* NO MEASURE HERE, AND THAT IS THE POINT. This carried max-width:var(--mw-read), which is
   the third instance of a fault .intnote and .intexp .factline both removed with
   the same argument: "nothing is indented, the right edge is pulled in, and the
   eye cannot tell those apart". At the 1600px shell it made a 400px paragraph
   sit under a full width heading with a thousand pixels of nothing beside it.
   The token's own min(100%,128ch) applies now, like every other .factline. */
.pageintro{padding:0;margin:0 0 var(--s-3)}
.errcard{text-align:center;padding:var(--s-5) var(--s-4)}
/* THE SUMMARY IS THE COLUMN PEOPLE ACTUALLY READ, so it gets the slack.
   It was capped at 340px over two lines, and real chat summaries run to 300 and
   400 characters, so a row showed roughly the first third of a sentence and
   stopped: "Wants room sizes and a turn key price on the..." tells a consultant
   nothing they can act on.
   A FLOOR IS NEEDED AS WELL AS A CEILING. The cap was not what was binding on a
   wide screen: the table is width:100% with auto layout, and the contact column
   carries a name, a mobile and an email, so it won the space and squeezed the
   summary well under its own max-width. min-width is what stops that.
   The floor is released entirely below 760px so the column can collapse rather
   than force the row wide, and .tblwrap scrolls if the sum still does not fit,
   which is the right failure for tabular data.
   Set on .leadsum directly rather than through custom properties on :root. These
   are page layout numbers, not design tokens, and tokens.css is the only place a
   token may be defined. */
/* ONE LINE, AND THE THREE MAX-WIDTH BREAKPOINTS ABOVE ARE GONE WITH IT.
 *
 * Clamped at three lines, a row was one, two or three lines tall depending on
 * how much the customer typed, so a board of twelve leads had five different row
 * heights and the eye had nothing regular to run down. On a queue, where the
 * whole job is scanning the first column, even rows are worth more than a third
 * line of somebody's enquiry: the full summary is one click away on the lead,
 * and the first line is what decides whether to click.
 *
 * The width juggling went because it is no longer this rule's problem. Those
 * three breakpoints existed to stop a long summary setting the Customer column's
 * width; the colgroup and table-layout:fixed on .board now decide every column
 * before any cell is read, so the clamp only has to say how tall. */
/* ---- THE BOARD'S COLUMN WIDTHS, AND THE SUM THAT HAS TO COME OUT UNDER 349 --
 *
 * These were inline styles on the <col> elements, which no class rule can reach
 * without an !important, so the phone breakpoint could not touch them and the
 * board scrolled sideways on every handset in the product.
 *
 * THE DESKTOP NUMBERS ARE UNCHANGED. Age is "1d 1h" over "15 Aug 7:38 pm",
 * Status is two pills side by side, and the action is sized for "Claiming...".
 *
 * THE PHONE NUMBERS ARE AN ARITHMETIC FIX AND THEY ARE NOT YET A MEASURED ONE.
 * At 375px the table gets 349px: .wrap pays --s-3 a side and the card two 1px
 * borders. .hide-sm removes Source, Owner and Account, leaving three fixed
 * columns and Customer taking the remainder. 68 + 92 + 76 is 236, which leaves
 * Customer 113px, against 456 and nothing before this change.
 *
 * Status loses the most because it loses the most cheaply: 212px buys two pills
 * on one line, and stacked they need about 90. The action carries "Claim". Age
 * keeps enough for the age itself and lets the arrived line wrap, which it has
 * room to do because the cell is already two lines tall.
 *
 * WHOEVER RUNS THE DEVICE PASS SHOULD TUNE THESE THREE NUMBERS, and they are in
 * one place so that is a one line change rather than a hunt through a template
 * literal. They were chosen off the stylesheet rather than off a handset,
 * because this app cannot be opened in a preview pane. */
.board col.c-age{width:116px}
.board col.c-src{width:132px}
.board col.c-status{width:212px}
.board col.c-owner{width:124px}
.board col.c-acct{width:160px}
.board col.c-act{width:128px}
/* THE RESERVED BUSY WIDTH, VIA A PROPERTY A BREAKPOINT CAN OVERRIDE.
   reserveBusyWidth measures the button's busy label once and pins it, so a
   button does not resize under the thumb that pressed it. On a desk that
   resolves to the same pixel value it always did. */
button[data-busy]{min-width:var(--busyw,auto)}
@media(max-width:720px){
  .board col.c-age{width:68px}
  .board col.c-status{width:92px}
  /* 88 rather than 76: the resting "Claim" is about 62px and the cell pays 24
     of gutter, so 76 clipped the button it was sized for. The 12px comes off
     Customer, which has the remainder and can give it. */
  .board col.c-act{width:88px}
  /* The reservation is dropped and the label ellipsises instead. max-width
     keeps the button inside its cell, which is what stops the clipping coming
     back the moment the label changes to "Claiming...". */
  .board td button[data-busy]{--busyw:auto;max-width:100%;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* Two pills side by side is what 212px bought, and at 92 they have to stack.
     THEY DO NOT STACK ON THEIR OWN. statusPill and flagPills are concatenated
     with no whitespace between them, so there is no soft wrap opportunity, and
     table.board td carries overflow:hidden (shell.css:370). Left alone the
     second pill would be clipped rather than moved to a second line, which is
     the worst of the three outcomes: an escalated lead that does not look
     escalated. A wrapping flex container gives them the opportunity the markup
     does not. */
  .board td.pills{display:flex;flex-wrap:wrap;gap:2px;align-content:flex-start}
}
.leadsum{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* THE THIRD LEVEL, AND IT IS A LEVEL RATHER THAN AN ACCIDENT. Kept at
   --fs-label on purpose while .cs and .factline collapsed into one, because an
   in-table hint like "Away" or "Outside hours now" sits inside a row that
   already carries meta text, and a third step is the only thing that keeps it
   subordinate to the cell it qualifies. Do not fold this into .factline: the
   two are not the same job, and the reason they look similar is that they are
   adjacent steps on one scale. */
.subline{font-size:var(--fs-label);color:var(--faint);display:block;margin-top:1px}
/* .childrow named the hierarchy indent since a6bd337 with no rule behind it: a
   child account's name rendered flush with its parent's. Now backs that class
   and the same indent on the rolled up Who to ring table's store rows. */
.n.childrow{padding-left:var(--s-6)}
/* The customer's name is the heading of its own row now that the mobile, the
   email and the summary sit under it rather than in three columns of their own.
   It takes the treatment td.n gives a name in a column to itself, set on the
   name alone so the lines beneath it are not dragged into navy with it. */
.cname{display:block;color:var(--navy);font-weight:var(--fw-med)}
/* The source, on one line. The summary keeps a 300px floor and takes its room
   from whatever is beside it, which squeezed "Live chat" into two lines: a two
   word label broken in half reads as two values. Capped in ch so an unexpected
   source name ellipsises rather than setting the width of the table. */
.srcname{display:inline-block;vertical-align:bottom;max-width:16ch;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ---- the attention band ------------------------------------------------------
 * A pill, the account when the scope spans more than one, and a sentence. Three
 * columns on a desk so the pills line up and the eye reads down them.
 *
 * ON A PHONE IT IS THREE LINES, NOT THREE COLUMNS. A nowrap account name in a
 * column of its own took two thirds of a 375px screen and left the sentence
 * wrapping one or two words to a line down a 130px gutter. Stacked, each row is
 * a state, a client and a sentence, in that order, at full width.
 *
 * The widths are in a min-width query rather than on the cells. Set on the cells
 * they would have to be undone below the breakpoint, and a width on a cell the
 * phone rule has just turned into a block is a cell one per cent wide. */
@media(min-width:721px){
  .band .bp,.band .ba,.band .bx{width:1%;white-space:nowrap}
}
@media(max-width:720px){
  /* A WRAPPING FLEX ROW, NOT FOUR BLOCKS AND A NEGATIVE MARGIN. The pill and the
     account each take a line; the sentence and the dismiss X share the last one,
     which is what the negative margin was faking. It faked it by pulling an
     opaque 44px button up 16px onto the sentence, where it painted over the end
     of it: "nobody has claimed it" lost its last two words behind the control
     that dismisses it. The sentence now has a real track to shrink into and the
     X sits beside it rather than on it. */
  .band,.band tbody{display:block}
  .band tr{display:flex;flex-wrap:wrap;align-items:flex-start;
    border-bottom:1px solid var(--line);padding:var(--s-2) 0}
  .band tr:last-child{border-bottom:0}
  /* THE CARD GUTTER ON EVERY CELL, AND THE EARLIER FIX ONLY GOT TWO OF THEM.
     This paid --s-3 with the outer edges restated at --s-4, which is right for
     a table with columns. There are no columns here: every cell is a line, so
     the middle one was simply the sentence, sitting 4px left of the .chead
     above it and the .factline below it. That is the exact fault the
     restatement was written to fix, half fixed, because it still pictured a
     three column row. */
  .band td{flex:1 1 100%;border-bottom:0;padding:1px var(--s-4)}
  .band td.ba{font-size:var(--fs-meta)}
  /* min-width:0, or a long sentence refuses to shrink and pushes the X off the
     row, which is the same fault one layer out. */
  .band td.bs{flex:1 1 0;min-width:0}
  .band td.bx{flex:none;padding-left:var(--s-2)}
}
/* THE DISMISS CONTROL. Quiet at rest, because it sits once per row on a card
   whose job is to draw the eye to the rows themselves, and a column of six
   buttons competing with six pills is a card with no focus at all. It takes the
   product's standard quiet treatment: an outline that only appears under the
   pointer, and the navy fill on hover that every demoted button here uses.

   32px, which is under the 44px this product holds itself to for a PRIMARY tap
   target and is deliberate: dismissing is the smallest, most reversible act on
   the page, and the row behind it opens the lead, so a fat target here would
   make the destructive-feeling thing easier to hit than the useful one. */
.bandx{background:none;border:1px solid transparent;color:var(--faint);
  font-size:18px;line-height:1;padding:0;width:32px;height:32px;border-radius:var(--r-sm);
  cursor:pointer;font-family:var(--sans)}
.bandx:hover{background:var(--navy);border-color:var(--navy);color:#fff}
.bandx:focus-visible{outline:2px solid var(--navy);outline-offset:1px}
.bandx[disabled]{opacity:.5;cursor:not-allowed}
/* A contact line is smaller than the name and still blue. Blue means tappable
   everywhere on this board, and a mobile number that does not look tappable is
   the one thing in the cell somebody is reaching for. `.subline` alone would
   win on specificity over `td a` and grey it out. */
a.subline{color:var(--blue-d)}
a.subline:hover{text-decoration:underline}
@media(max-width:720px){
  /* .subline sets display:block in this block, which is later in the cascade
     than shell.css's .hide-sm and matches at the same weight, so a subline
     marked hide-sm needs both classes together to win. */
  .subline.hide-sm{display:none}
}
/* WRAP, BECAUSE WITHOUT IT THIS ROW DELETES A BUTTON RATHER THAN HIDING ONE.
   Three buttons end the onboard card: Activate without payment, Create the
   payment link, Start the 7 day trial. Roughly 518px of labels, all nowrap, in
   a 370px track on a phone. justify-content:flex-end sends every pixel of the
   overflow off the START edge, where there is no scrollbar and nothing to drag,
   and .card's overflow:hidden then destroys it: the first button renders as
   "yment". That is worse than a sideways scroll, which at least keeps the
   content. One word fixes it and desktop never sees it, because at 1600px the
   row has roughly a thousand pixels and nothing wraps. The other two call sites
   are single button cells. */
.rowacts{display:flex;flex-wrap:wrap;gap:var(--s-1);justify-content:flex-end;white-space:nowrap}
/* .pillbtn IS RETIRED. It was a ninth button treatment invented for exactly one
   control, the alerts toggle on Integrations, and its own comment described the
   problem rather than a reason: "reads as the pill it replaces until you are
   near it, then behaves like the control it is". A thing that looks like a
   status and is actually a switch is a thing nobody presses, and the product
   already HAS a switch component, in tokens.css, used for every other boolean
   in every dense admin table. One switch, one meaning, everywhere.
   The label beside it is what turns "a toggle" into "alerts are on". */
.altsw{display:inline-flex;align-items:center;gap:var(--s-2);font-size:var(--fs-body);color:var(--ink);cursor:pointer}
.altsw .st{font-weight:var(--fw-med)}
.cols{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:var(--s-3);align-items:start}
.cols.demo{grid-template-columns:minmax(0,1.25fr) minmax(0,1fr)}
@media(max-width:900px){.cols,.cols.demo{grid-template-columns:minmax(0,1fr)}}
/* Every direct child of a two column layout has to be allowed to be narrower
   than its widest content, or a table inside it sets the width of the page. */
.cols>*{min-width:0}
/* The stack of cards in the demo console's right rail. It was an inline grid
   style, and its tracks defaulted to auto, so the cards inside it could not
   shrink and pushed the whole page 30px wider than a phone. */
.railstack{display:grid;gap:var(--s-3);min-width:0}
.railstack>*{min-width:0}
/* event timeline (lead detail) */
.tl{list-style:none;margin:0;padding:var(--s-1) 0}
.tl li{display:grid;grid-template-columns:92px 20px 1fr;gap:0 var(--s-2);position:relative}
.tl .when{font-size:var(--fs-meta);color:var(--mut);font-variant-numeric:tabular-nums;text-align:right;padding-top:1px}
.tl .when small{display:block;font-size:var(--fs-label);color:var(--faint)}
.tl .rail{position:relative}
.tl .rail::before{content:"";position:absolute;left:9px;top:18px;bottom:-4px;width:1px;background:var(--line)}
.tl li:last-child .rail::before{display:none}
.tl .tdot{position:absolute;left:5px;top:5px;width:9px;height:9px;border-radius:50%;background:#fff;border:2px solid var(--n-400)}
.tl li.act .tdot{border-color:var(--navy);background:var(--navy)}
.tl li.bad .tdot{border-color:var(--status-alert-txt)}
.tl li.note .tdot{border-style:dashed}
.tl .tbody{padding:0 0 var(--s-4)}
/* ONE MEASURE PER BLOCK, ON EVERY LINE IN IT AND NOT JUST THE LONG ONE. A
   description capped at the read measure beside a title with no cap gives one
   block two right edges, and the eye reads that as the shorter line being
   indented rather than as the longer one running on. Same argument .gd-lead,
   .gd-t and .gd-d were collapsed onto one measure for. */
.tl .t{font-size:var(--fs-body);color:var(--ink);font-weight:600;max-width:var(--mw-read)}
.tl .d{display:block;font-size:var(--fs-meta);color:var(--mut);margin-top:1px;max-width:var(--mw-read);line-height:var(--lh-body)}
/* ---- fact rows: label and value ON ONE LINE ---------------------------------
 * This is the most repeated block in the product and it was the loudest.
 *
 * Before: an uppercase tracked eyebrow with the value stacked underneath it. A
 * column of five of those shouts five times for five facts nobody asked about
 * in that order, doubles the height of every short value, and leaves the info
 * button hanging off the caps rather than sitting with the text it annotates.
 * Measured in the mock: the row went from about 86px to 40px.
 *
 * SENTENCE CASE, AND THAT IS THE SAME DECISION AS THE TABLE HEADERS. Small caps
 * survive only where they mark structure, meaning a section kicker. An eyebrow
 * on every row of every card is grammar nobody chose.
 *
 * THE LABEL COLUMN IS FIXED AT 156px, WHICH IS THE POINT. Every value in a card
 * starts at the same x, so five facts read as one column of answers instead of
 * five independently indented lines. align-items:baseline, not center, or a
 * value that wraps to two lines drags its label down with it.
 *
 * It stacks below 640px, where 156px is a quarter of the screen. */
/* THE 156px LABEL COLUMN WAS WRITTEN FOR A FULL WIDTH CARD AND .facts IS NOW IN
   TEN PLACES, SEVERAL OF THEM NARROW. On the lead page it sits in a ~345px rail,
   where 156px plus the gutter leaves about 130px for the value, and the row was
   flex:0 0, so the label could not give any of it back. A value with no break
   opportunity then had nowhere to go: testing@testing.com and
   "8/12/2026 04:55 PM AEST" both ran straight through the card's right border.
   Reported by Chirag with a screenshot of exactly those two rows.

   THREE THINGS WERE WRONG AND ALL THREE HAD TO CHANGE.

   flex:0 0 156px never shrinks, so the label kept its full width in a rail half
   its natural size. It is 0 1 now with a floor, so it gives ground before the
   value overflows and still never collapses to nothing.

   min-width on a flex item defaults to auto, which floors it at its own
   min-content width. For an email address that is the whole string, so the item
   refused to shrink whatever the container did. overflow-wrap:anywhere is what
   changes that: unlike break-word it reduces min-content too, so the floor
   drops and the value wraps instead of escaping. The label opts back out, or
   "Time to claim" would break mid-word.

   .num carries white-space:nowrap from shell.css, correctly, so a number is
   never split across lines. A formatted timestamp is not one number though, it
   is a date, a time and a zone, and inside a fact row it has to be allowed to
   wrap between them. Scoped here, so every other .num on the product is
   untouched. */
.facts .frow{display:flex;gap:var(--s-4);align-items:baseline;
  padding:var(--s-2) var(--s-4);border-bottom:1px solid var(--line);font-size:var(--fs-body);
  overflow-wrap:anywhere}
.facts .frow:last-child{border-bottom:0}
/* AND A CEILING, ADDED AFTER THE FIRST GO WAS ONLY HALF RIGHT. Letting the
   label shrink stopped the value escaping the card, and it still shrank only as
   far as it had to, so testing@testing.com broke mid-word into "testing@testing.c
   / om" and the timestamp wrapped onto two lines. That is the wrapping working
   and the column still being wrong.

   156px was tuned for a full width card. In this 345px rail it is nearly half
   the row, for labels whose longest is "Time to claim" at about 86px. A
   percentage ceiling fixes both shapes with one number: 38% of a 313px content
   box is 119px, which fits every label with room to spare and hands the value
   back about 60px, enough for both of those strings on one line. On a wide card
   38% is larger than 156px, so the flex-basis still wins and nothing there
   changes. */
.facts .frow .lbl{flex:0 1 156px;min-width:84px;max-width:38%;overflow-wrap:normal;
  font-family:var(--sans);font-size:var(--fs-meta);
  font-weight:var(--fw-med);text-transform:none;letter-spacing:normal;color:var(--mut);margin:0}
.facts .frow a{color:var(--blue-d);text-decoration:none;font-weight:600}
.facts .frow .num{white-space:normal}
@media(max-width:640px){
  .facts .frow{display:block}
  .facts .frow .lbl{display:block;margin-bottom:2px}
}
/* ---- whatever else the customer told us ------------------------------------
 * THE PROBLEM THIS SOLVES, IN THE CLIENT'S WORDS: "I don't have the bandwidth
 * to create individual templates for the live chat leads or whatever lead comes
 * through, but I want a way for it to nicely appear on the front end without me
 * having to map every one of them."
 *
 * A lead carries a jsonb of whatever its intake sent: suburb, postcode, state
 * from a chat widget, block size from a builder, vehicle of interest from a
 * dealer, and things nobody has thought of yet. There is no schema, there never
 * will be, and a product that needs a developer before a new field can be seen
 * is a product that never shows it.
 *
 * WHY CHIPS AND NOT MORE ROWS. The eight that matter (name, contact, where they
 * are, what they want) stay as .facts rows, because those are read top to bottom
 * and compared between leads. The rest is a bag of unknown size whose keys are
 * unknown, and a fifteen row table of one-word values is a wall. As chips they
 * wrap to the width available, a lead with three extras takes one line and a
 * lead with twenty takes four, and neither has to be designed for.
 *
 * --r-sm and not --r-pill, deliberately. The client asked for "little gray
 * buttons of text" and a pill reads as a status, which these are not: every
 * other pill in this product says something about the state of a lead. A soft
 * rectangle on the neutral ramp reads as data, and it is the same 8px radius as
 * every real button on the page, which is what makes it look like it belongs.
 *
 * Not clickable, and no hover. They carry information rather than actions, and a
 * chip that lifts under the cursor is a chip somebody will click. */
.kvchips{display:flex;flex-wrap:wrap;gap:var(--s-2);margin:0;padding:0;list-style:none;min-width:0}
.kvchip{display:inline-flex;align-items:baseline;gap:var(--s-2);max-width:100%;min-width:0;
  font-size:var(--fs-meta);background:var(--n-50);border:1px solid var(--n-200);
  border-radius:var(--r-sm);padding:3px var(--s-2) 4px;overflow-wrap:anywhere}
/* The key is set as a label and the value as content, which is the same
   relationship .facts draws with a 156px column and the same one the eye needs
   here. Without the case and tracking difference a chip reads as two words. */
.kvchip .k{flex:none;font-family:var(--display);font-size:var(--fs-label);font-weight:var(--fw-semi);
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--faint);white-space:nowrap}
.kvchip .v{min-width:0;color:var(--ink)}
/* The enquiry in the customer's own words. It is the one field on a lead that is
   a paragraph rather than a value, so it is never a chip and never a table row:
   it gets a measure and room to be read. */
.leadsummary{font-size:var(--fs-body);color:var(--ink);line-height:var(--lh-body);
  background:var(--n-50);border-radius:var(--r-sm);padding:var(--s-3) var(--s-4);
  margin:0;max-width:var(--mw-wide);white-space:pre-wrap;overflow-wrap:anywhere}
/* THE SAME BLOCK WHEN THE INTAKE SENT A LIST. Three leads carry eight separate
   things the customer said, flattened by the widget into one JSON string, so
   .leadsummary above rendered them as one paragraph of brackets and quotes and
   the consultant had to parse punctuation to find them. Same box, same measure,
   same reading treatment: only the shape inside it changes, because it is still
   the customer's own words and still belongs to the block above. Discs, unlike
   the claim page, because here there is no label column doing that job. */
.leadlist{font-size:var(--fs-body);color:var(--ink);line-height:var(--lh-body);
  background:var(--n-50);border-radius:var(--r-sm);padding:var(--s-3) var(--s-4);
  margin:0;max-width:var(--mw-wide);overflow-wrap:anywhere;list-style:disc;padding-left:calc(var(--s-4) + 1.1em)}
.leadlist li{white-space:pre-wrap}
.leadlist li+li{margin-top:var(--s-2)}
/* ONE WIDTH FOR EVERY CONTROL IN THE ROW, WITHOUT A MAGIC NUMBER.
   Chirag: "resize the 3 buttons so they are all sized the same". They were flex
   items, so each was as wide as its own word and Text sat visibly narrower than
   Close lead.

   grid-auto-columns:1fr rather than a min-width in pixels. Every track is sized
   to the widest content in the row, so the three agree by construction and go on
   agreeing when a label changes: "Close lead" becoming "Close this lead" moves
   all three together instead of leaving a guessed 110px looking wrong. A pixel
   floor would have had to be re-measured by eye in a browser this app cannot be
   previewed in.

   justify-content:end keeps the row against the right edge of the page head,
   which display:flex was doing for free and grid is not.

   .txtwrap is the grid item for Text, not its button, because textBoxHtml wraps
   it to anchor the message popover. It stretches so the button inside can fill
   the track it was given. */
.pagehead .actions{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
  gap:var(--s-2);align-items:center;justify-content:end}
.pagehead .actions>*{min-width:0}
.pagehead .actions .txtwrap{display:grid}
/* THE SWITCH, ITS LABEL AND ITS i BUTTON ARE ONE CONTROL, NOT THREE 1fr TRACKS.
   Wrapped in the demo header markup so grid-auto-columns:1fr above sizes them
   as a single track instead of three equal-width ones, which is what spread
   them across the page. Scoped to this class: no other page builds it. */
.presctl{display:flex;align-items:center;gap:var(--s-2)}
/* :not(.i) IS THE FIX FOR THE ELLIPSE, AND THE ELLIPSE HAD THREE CAUSES.
   The i-button is a <button>, so this blanket rule caught it and set it to
   width:100%. Its track is 1fr because of grid-auto-columns above, so a control
   declaring width:24px and height:24px with border-radius:50% rendered about
   150px wide and 24px tall: a circle stated in shell.css and drawn as an
   ellipse on every page whose head carries one.

   The guard that should have stopped it was already there and could not work.
   .i declares flex:none, which is a flex property on an element whose parent is
   a grid, so it is not overridden, it is unreachable. That is the third time on
   this project that a guard has been silently inert because the layout model
   changed underneath it. It is left in place because .i sits in flex parents
   elsewhere, where it does work. F7 is the sweep for the rest of the class. */
.pagehead .actions button:not(.i),
.pagehead .actions a.btn-primary{width:100%;justify-content:center;text-align:center}
/* Sized by shell.css and centred in the track it was given rather than filling
   it. Intrinsic, so it cannot be stretched by a rule that meant the buttons. */
.pagehead .actions .i{width:24px;flex:none;justify-self:center}
/* ---- texting the customer ---------------------------------------------------
 * A SMALL BOX, NOT A MODAL. The message is one sentence that is already written,
 * so the common case is read it and send it. A modal would dim the lead behind
 * it, and the lead is the thing being read to decide whether that sentence is
 * the right one, so the box hangs off the button that opened it and leaves the
 * page alone. Escape closes it without sending.
 *
 * THE CUSTOMER'S NUMBER IS NOT IN HERE AND MUST NEVER BE. It is not returned by
 * the send and it is not read off the lead: the number is resolved server side
 * and the four narrowings that keep it there are the reason this box shows who
 * the text is going to only as "the customer".
 *
 * ANCHORED TO THE PAGE HEAD, NOT TO THE BUTTON, and that is the difference
 * between a box on screen and one hanging off the left of a phone. The head wraps
 * on a narrow viewport: the title keeps the first line and the actions drop to the
 * second hard against the left gutter, so a box hung off the button's own right
 * edge started 257px off the left of a 375px screen. The head is the full content
 * width at every size, so right:0 against it is the right edge of the page.
 *
 * Capped against the viewport rather than given a width it cannot keep. The page
 * gutter is 20px a side, so calc(100vw - 40px) is the widest it can be without
 * putting a horizontal scrollbar on a phone. */
.pagehead{position:relative}
.txtwrap{display:inline-flex}
.txtbox{position:absolute;top:100%;right:0;z-index:40;width:330px;
  max-width:calc(100vw - 40px);background:var(--card);border:1px solid var(--line);
  border-radius:var(--r-md);box-shadow:var(--sh-modal);padding:var(--s-3);text-align:left}
.txtbox textarea{display:block;width:100%;box-sizing:border-box;margin-top:var(--s-1);
  font-family:var(--sans);line-height:var(--lh-body);
  padding:var(--s-2) var(--s-3);border:1px solid var(--line-strong);border-radius:var(--r-sm);
  color:var(--ink);background:var(--card);resize:vertical;min-height:88px}
.txtbox textarea:focus{outline:none;border-color:var(--navy);box-shadow:var(--focus-ring)}
.txtfoot{display:flex;gap:var(--s-2);align-items:center;margin-top:var(--s-2)}
.txtfoot .sp{flex:1 1 auto}
/* The count is the only warning there is: the server refuses a long message and
   never truncates it, so over the limit is a state and not a nudge. */
.txtct{font-size:var(--fs-meta);color:var(--mut);font-variant-numeric:tabular-nums}
.txtct.over{color:var(--status-alert-txt);font-weight:var(--fw-semi)}
.txtmsg{font-size:var(--fs-meta);color:var(--status-alert-txt);line-height:var(--lh-snug);
  margin:var(--s-2) 0 0;max-width:none}
/* Collapsed rather than display:none, because it is the box's live region. A
   display:none element is not in the accessibility tree, so the region would only
   be registered at the moment it filled and a refusal announced to nobody. Zero
   height and no margin costs nothing and keeps it there. */
.txtmsg:empty{margin:0;height:0;overflow:hidden}
/* .strip, .tile and .panel WERE HERE AND WENT WITH THE PAGE THAT USED THEM.
   The metric tiles were Reporting's tab bar and the panel was the body under
   them. Nothing else in the product drew one: checked selector by selector
   before removing them, because a class kept "in case" is a class the next
   reader has to prove is dead all over again. Reporting is Metabase now,
   docs/decisions/0020, and DC-59 took the page. */
/* MORE SPACE ABOVE A HEADING THAN BELOW IT. A section heading sat 16px from the
   section before it and 8px from its own content, which is nearly symmetrical,
   and a heading with equal space either side belongs to neither the thing above
   nor the thing below. 24px above and 8px below binds it to what it names. */
.sect{margin:var(--s-5) 0 0}
.sect:first-child{margin-top:0}
.sect:last-child{margin-bottom:0}
.sect h3{font-family:var(--display);font-size:var(--fs-meta);font-weight:600;margin:0 0 var(--s-2);color:var(--n-600)}
/* A section heading that carries an infotip keeps the same spacing as one that
   does not, or two sections on the same page start at different heights. */
.sect>.ctitle{margin:0 0 var(--s-2)}
.sect>.ctitle h3{margin:0}
.foot{font-size:var(--fs-meta);color:var(--mut);margin:var(--s-2) 0 0}
.foot b{color:var(--n-600);font-weight:600}
/* .statpair went with .tile: it drew the median and fastest claim figures under
   Reporting's time-to-claim panel and nowhere else. */
/* team */
/* THE COLUMN TEMPLATE COMES THROUGH A CUSTOM PROPERTY, and that is not a
   flourish. Ten of these forms set their own template with an inline style, and
   an inline style beats a media query, so every one of them stayed in four
   columns on a phone and pushed the page 225px wider than the screen. Routed
   through --cols, the inline value only feeds the default, and the query below
   overrides the property itself and wins. */
.repform{display:grid;grid-template-columns:var(--cols,1fr 1.2fr 1fr auto);gap:var(--s-2);align-items:end;
  padding:var(--s-3) var(--s-4);border-top:1px solid var(--line);min-width:0}
.repform>*{min-width:0}
/* The submit and its cancel, sharing the one grid cell so adding a cancel does
   not shift every field beside it. */
.repformacts{display:flex;gap:var(--s-2);align-items:end}
@media(max-width:720px){.repform{grid-template-columns:1fr}}
/* A BUTTON THAT LOOKS LIKE A LINK IS THE WRONG ONE OF THE TWO. This opens the
   hours editor: it changes something, it does not go anywhere, and a blue
   underlined word is the product's own established signal for a tel: or mailto:
   link. It takes the quiet treatment every other secondary action takes, which
   also gives it an edge to hit rather than seventeen pixels of text. */
.hoursbtn{background:var(--n-0);color:var(--navy);border:1px solid var(--line-strong);
  border-radius:var(--r-sm);padding:2px var(--s-2);font-family:var(--display);
  font-size:var(--fs-meta);font-weight:var(--fw-semi);cursor:pointer;text-align:left}
.hoursbtn:hover{background:var(--navy);color:#fff;border-color:var(--navy)}
.hoursbtn:focus-visible{outline:2px solid var(--navy);outline-offset:1px}
/* ---- the consultant row and what sits behind it -----------------------------
 * The row is a name, a mobile and whether they are on. Everything else about
 * the consultant opens underneath it in a panel that is a table row of its own,
 * so the four columns above keep their alignment.
 *
 * NO MOTION ON THIS ONE, DELIBERATELY, AND IT WAS ALSO THE ONLY THING THAT
 * WORKED. The integrations disclosure eases its own grid track from 0fr to 1fr,
 * which is the one authored motion moment in this product, and it stays the
 * one: a second animated disclosure repeated down a table of consultants is an
 * entrance animation per row wearing a different hat. It is also not available
 * here. Inside a table cell an fr track resolves against a height the table has
 * not decided yet, so 1fr measured zero and the panel opened to nothing. The
 * row shows and hides. The chevron turning is the only movement, which is the
 * same treatment the integrations row gives its own chevron.
 *
 * display:none rather than a height of zero, so a closed panel is out of the
 * tab order rather than a set of controls somebody can reach and not see. */
tr.reprow{cursor:pointer}
tr.reprow:hover td{background:var(--n-25)}
tr.reprow:focus-visible{outline:2px solid var(--navy);outline-offset:-2px}
tr.repdet{display:none}
tr.repdet.open{display:table-row}
tr.repdet>td{padding:0}
/* --s-4 AND NOT --s-3 ON THE HORIZONTAL. tr.repdet>td zeroes the cell, which is
   right because the panel paints its own inset, but the value it reintroduced
   was 12 while the consultant's name in the row directly above sits at 16. Open
   the panel and everything in it stepped 4px left of the person it is about. */
.repdetin{padding:var(--s-1) var(--s-4) var(--s-3)}
tr.repdet .facts .frow{padding:var(--s-2) 0}
tr.repdet .facts .frow:first-child{border-top:0}
.repch{text-align:right;width:1%;white-space:nowrap}
.repmore{display:inline-flex;align-items:center;justify-content:center;min-width:34px}
.repmore .chev{transition:transform 160ms ease-out}
.repmore[aria-expanded=true] .chev{transform:rotate(180deg)}
@media(prefers-reduced-motion:reduce){ .repmore .chev{transition:none} }
.repacts{display:flex;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-3)}
/* ---- two subjects in one card ------------------------------------------------
 * A rule across the card and a small heading, never a card inside a card. The
 * account page was emitting four cards for what is one subject, and the
 * alternative to a stack of cards is not a nested one. Each section supplies its
 * own gutter, so the shared .card .factline gutter is reset inside it rather
 * than doubling into an indent. */
.csect{padding:var(--s-3) var(--s-4) var(--s-4);min-width:0}
.csect+.csect{border-top:1px solid var(--line)}
.csect>h3{font-family:var(--display);font-size:var(--fs-meta);font-weight:var(--fw-semi);
  color:var(--n-600);margin:0 0 var(--s-2)}
/* Same as .intexp .factline below: the cap is off and the token's own applies.
   72ch was the same defect one card over, and .csect is used on Team, on the
   test lead composer and on the lead detail page, so it was the widest spread
   of the three. */
.csect .factline{padding:0;margin:0 0 var(--s-3)}
.csect .repform{padding:0;border-top:0}
.csect>*:last-child{margin-bottom:0}
/* The leaver block. Set apart because it is the one thing on this page with a
   deadline attached to it, and stated because Reset links and Remove are not
   the same action and a row of two red buttons would read as though they were. */
.leaver{margin-top:var(--s-3);padding-top:var(--s-3);border-top:1px solid var(--line)}
.leaver .lhd{font-family:var(--display);font-size:var(--fs-meta);font-weight:var(--fw-semi);
  color:var(--n-600);margin:0 0 var(--s-1)}
.leaver .factline{padding:0}
/* ---- enquiry fields: a hairline row list, not a six column table ------------
 * The table this replaces had a minimum width of about 614px, so on a 375px
 * phone it scrolled 240px sideways inside its own card and the two switches that
 * decide what a consultant sees were off screen with nothing saying so.
 *
 * A row wraps instead of scrolling: name on top, controls underneath, which is
 * the behaviour a table cannot have. min-width:0 on the name column is what lets
 * a long key ellipsis rather than pushing the switches off the end, and it is
 * the same trap .tblwrap and .zones both carry a note about. */
.frow2{border-bottom:1px solid var(--line)}
.frow2:last-of-type{border-bottom:0}
.fmain{display:flex;align-items:center;gap:var(--s-4);flex-wrap:wrap;
  padding:var(--s-2) var(--s-4)}
.fname{flex:1 1 260px;min-width:0}
.fieldtbl input.flab{padding:var(--s-1) var(--s-2);height:34px;min-width:0}
.fmeta{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin-top:2px}
/* The upstream key IS an identifier, so monospace is correct here and is the
   only place on this card it is. */
.fkey{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:var(--fs-label);color:var(--mut);overflow:hidden;text-overflow:ellipsis}
.fseen{font-size:var(--fs-label);color:var(--faint)}
.ftog{display:flex;align-items:center;gap:var(--s-4);flex:none;flex-wrap:wrap}
.ftog .altsw .st{font-size:var(--fs-meta);color:var(--mut);font-weight:var(--fw-body)}
/* Set once and then never, so it lives behind More: order, and the one
   destructive control on the card. */
.fdet{display:flex;align-items:end;gap:var(--s-3);flex-wrap:wrap;
  padding:0 var(--s-4) var(--s-3) var(--s-4)}
.fdet label{margin:0}
.fieldtbl input.fpos{width:80px;padding:var(--s-1) var(--s-2);text-align:right}
@media(max-width:640px){
  .fmain{gap:var(--s-2)}
  .ftog{width:100%;justify-content:space-between;gap:var(--s-2)}
}
/* .kpis+.kpis{margin-top:-8px} IS GONE WITH THE SECOND STRIP. It welded two
   independently bordered strips together and left a visible 6px trench where
   the two borders met. Two strips that need a negative margin to look like one
   strip were always one strip, and both are now in the right rail. */
.kpinote{display:block;font-size:var(--fs-meta);color:var(--mut);margin-top:3px;
  text-transform:none;letter-spacing:normal;font-weight:var(--fw-body)}

/* The status pills under a lead's page head. It was a bare div with an inline
   margin:-6px 0 14px, pulling itself back up into the head to close a gap that
   belonged to the head's own margin: a negative-margin orphan between two blocks
   that were each correct on their own. Normal spacing, and the head keeps its. */
.leadpills{display:flex;flex-wrap:wrap;gap:var(--s-2);margin:0 0 var(--s-4)}
/* .outraw WAS HERE AND WENT WITH THE OUTCOME KEY, B3. It set the database's own
   enum in monospace beside the English one. The reasoning was sound, monospace
   is for identifiers, and the fault was one level up: the raw enum was on a
   client screen at all, and this was the only place it appeared, since the log
   itself keeps it on the hover. */

/* ---- the right rail ---------------------------------------------------------
 * Three figures that change today, large, and six that describe the last sixty
 * days, compact. Both were 32px tiles across the top of the board, which is nine
 * things claiming to be the most important thing above the one that is. */
.railcard .chead{padding:var(--s-2) var(--s-3)}
.railcard .chead h2{font-size:var(--fs-body)}
.railbig{padding:var(--s-3)}
.railbig .rb+.rb{margin-top:var(--s-3);padding-top:var(--s-3);border-top:1px solid var(--line)}
.railbig b{display:block;font-family:var(--display);font-size:var(--fs-stat);
  font-weight:var(--fw-semi);color:var(--navy);line-height:var(--lh-tight);
  letter-spacing:var(--tr-tighter);font-variant-numeric:tabular-nums}
/* A duration reads as a word, so it takes the step below the count beside it
   rather than being set at the same size and wrapping. */
.railbig b.txt{font-size:var(--fs-page)}
/* Waiting is the one figure on this page somebody acts on, so it is the one
   allowed to change colour when it is not zero. */
.railbig b.hot{color:var(--status-alert-txt)}
.railbig span{display:block;font-size:var(--fs-label);font-weight:var(--fw-semi);
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--faint);margin-top:2px}
/* A real <dl>, because that is what a list of labels and values is. */
.raillist{margin:0;padding:var(--s-2) var(--s-3)}
.raillist>div{display:flex;align-items:baseline;justify-content:space-between;
  gap:var(--s-3);padding:var(--s-1) 0}
.raillist dt{font-size:var(--fs-meta);color:var(--mut);min-width:0}
.raillist dd{margin:0;font-family:var(--display);font-weight:var(--fw-semi);
  font-size:var(--fs-body);color:var(--ink)}
@media (max-width:1240px){
  /* Folded to a strip, the two cards sit side by side and the big figures go
     back to a row rather than a column. */
  .railbig{display:flex;gap:var(--s-4)}
  .railbig .rb+.rb{margin-top:0;padding-top:0;border-top:0}
  .raillist{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:0 var(--s-4)}
}

/* ---- a sortable column header -----------------------------------------------
 * The header IS the button, so the whole cell is the target rather than a word
 * inside it. Inherits the th's own type so a sortable column and a plain one are
 * the same header with one of them operable. */
.sortbtn{display:inline-flex;align-items:center;gap:var(--s-1);width:100%;
  background:none;border:0;padding:0;margin:0;cursor:pointer;
  font:inherit;color:inherit;letter-spacing:inherit;text-align:left}
.sortbtn:hover{color:var(--navy)}
.sortbtn.on{color:var(--navy)}
.sortbtn:focus-visible{outline:2px solid var(--navy);outline-offset:2px}
.sortmark{font-size:var(--fs-label);line-height:1}

/* ---- elapsed time, the loudest thing in the row -----------------------------
 * The product's entire thesis, previously 14px grey text under nine 32px counts.
 * Larger and heavier than the customer name beside it, and it recolours past the
 * escalation window so the number the rules are read from says which side of
 * them it is on. */
td .age{display:block;font-family:var(--display);font-size:var(--fs-input);
  font-weight:var(--fw-bold);color:var(--navy);letter-spacing:var(--tr-tighter);
  font-variant-numeric:tabular-nums;white-space:nowrap;line-height:var(--lh-tight)}
td .age.late{color:var(--status-alert-txt)}
/* A legacy row is real history, not an alert and not a test, so it recedes
   rather than being marked. No hatching: that means test data and only test. */
tr.legacyrow td{color:var(--mut)}
tr.legacyrow td.n{color:var(--n-600)}
/* backloaded history marker: quiet, plain, and nothing like the dashed test tag */
.tag-hist{display:inline-block;font-family:var(--display);font-size:var(--fs-label);font-weight:600;
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--faint);
  border:1px solid var(--line);border-radius:4px;padding:1px var(--s-1);background:var(--n-25);
  white-space:nowrap}
/* Consultant hours editor. Seven fixed rows, day / on / start / finish, so the whole
   week is one glance and one tap per change. Sized to survive a 360px phone:
   the two time inputs share whatever is left after the day label and the
   switch, which is why they are 1fr and not a fixed width. */
.mc.hrs{max-width:400px;max-height:88vh;overflow:auto}
.avrow{display:grid;grid-template-columns:36px 36px 1fr 1fr;gap:var(--s-1);align-items:center;margin:0 0 var(--s-1)}
.avday{font-family:var(--display);font-size:var(--fs-meta);font-weight:600;color:var(--mut)}
.avrow input[type=time]{padding:var(--s-2) var(--s-1)}
.avrow input[type=time]:disabled{background:var(--n-50);color:var(--faint)}
.avfoot{display:flex;gap:var(--s-2);justify-content:flex-end;margin-top:var(--s-3)}
.avfoot .spread{margin-right:auto}
/* demo console */
.step{display:grid;grid-template-columns:34px minmax(0,1fr);gap:0 var(--s-3);padding:var(--s-3) var(--s-4);border-bottom:1px solid var(--line);align-items:start}
.step:last-child{border-bottom:0}
.snum{width:26px;height:26px;border-radius:50%;border:1px solid var(--n-300);color:var(--n-400);font-family:var(--display);font-size:var(--fs-meta);font-weight:700;display:flex;align-items:center;justify-content:center;margin-top:1px}
.step.active .snum{border-color:var(--navy);color:#fff;background:var(--navy)}
.step.done .snum{border-color:var(--status-active-line);color:var(--status-active-txt);background:var(--status-active-bg)}
.step .st{font-family:var(--display);font-size:var(--fs-body);font-weight:700;color:var(--n-500);letter-spacing:var(--tr-tight);max-width:var(--mw-read)}
.step.active .st,.step.done .st{color:var(--navy)}
/* Measure in ch, not px. A pixel width is only the right line length for one
   font size, so every prose block set in px drifts off measure the moment the
   scale moves. 68ch sits inside the 65 to 75 band at any step. */
.step .sd{font-size:var(--fs-meta);color:var(--mut);margin-top:2px;max-width:var(--mw-read);line-height:var(--lh-body)}
.step .sr{font-size:var(--fs-meta);color:var(--status-active-txt);margin-top:var(--s-1);font-weight:500;max-width:var(--mw-read)}
.step .shint{font-size:var(--fs-meta);color:var(--faint);margin-top:var(--s-1);max-width:var(--mw-read)}
.step .sbtns{display:flex;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-2);align-items:center}
/* minmax(0,1fr), not 1fr. A grid track defaults to min-width:auto, so an input
   with a long prefilled address in it refuses to shrink and pushes the whole
   page sideways on a phone instead of scrolling inside its own field. */
.step .fields{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s-2);margin-top:var(--s-2);max-width:430px}
.step .fields.one{grid-template-columns:minmax(0,1fr)}
@media(max-width:520px){.step .fields{grid-template-columns:minmax(0,1fr)}}
/* A refusal sits in the result slot, which is the teal a completed step uses,
   so it says so in the colour every other failure on this product uses. */
.step .sr .serr{color:var(--status-alert-txt)}
/* AN OFF STEP RECEDES BY COLOUR AND WEIGHT, NEVER BY TRANSPARENCY. opacity on
   text blends it toward whatever happens to be behind it, so the ratio it lands
   on is a property of the surface rather than of the token: at .55 on the card
   the title measured 3.66:1 and the description 2.33:1, both under the 4.5:1
   floor for body text. Stated as colours instead, on the card the title is
   5.88:1 and the description 4.97:1, and the step still reads as off because the
   title drops a weight and both drop a step down the neutral ramp. */
.step[data-off] .st{color:var(--n-500);font-weight:var(--fw-med)}
.step[data-off] .sd{color:var(--faint)}
.feed{list-style:none;margin:0;padding:var(--s-1) var(--s-4) var(--s-2);min-height:80px}
.feed li{display:grid;grid-template-columns:58px 1fr;gap:var(--s-2);padding:var(--s-1) 0;border-bottom:1px solid var(--n-50);font-size:var(--fs-meta)}
.feed li:last-child{border-bottom:0}
.feed .ft{color:var(--faint);font-variant-numeric:tabular-nums}
.feed .fb{color:var(--ink)}
.feed .fb b{color:var(--navy);font-weight:600}
.feedempty{padding:var(--s-5) var(--s-4);font-size:var(--fs-meta);color:var(--faint)}
.chanline{display:flex;gap:var(--s-3);align-items:center;flex-wrap:wrap;margin:0 0 var(--s-3);font-size:var(--fs-meta);color:var(--mut)}
/* Presenting switch. It sits in the page head beside a destructive button, so
   it is deliberately quiet: this is a view setting, not an action. */
/* 2px was off every scale in the product and put this switch on an edge nothing
   else shared. --s-1 is the step for the space inside a control group. */
.presw{margin-left:var(--s-1)}
.preslab{font-family:var(--display);font-size:var(--fs-meta);font-weight:600;color:var(--n-600);letter-spacing:var(--tr-label)}
/* A switch and its label. Not .avrow, which is the seven day hours grid and
   squeezes a sentence into a 36px column. */
.setrow{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-3) var(--s-4);font-size:var(--fs-body);
  color:var(--ink);border-top:1px solid var(--line);flex-wrap:wrap}
/* The same row inside a dialog, where the card's gutter and top rule belong to
   nothing. A class rather than an inline style: an inline style beats every
   media query below it, which is how a settings row survived a breakpoint it
   was meant to change at. */
.setrow.bare{border-top:0;padding:0}
.pn{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);padding:var(--s-4) var(--s-4)}
.pn b{display:block;font-family:var(--display);font-size:var(--fs-stat);line-height:1.02;font-weight:700;
  color:var(--navy);letter-spacing:var(--tr-tighter);font-variant-numeric:tabular-nums}
.pn span{display:block;font-size:var(--fs-label);font-weight:600;letter-spacing:var(--tr-label);text-transform:uppercase;
  color:var(--faint);margin-top:var(--s-2)}
.pn em{display:block;font-style:normal;font-size:var(--fs-meta);color:var(--mut);margin-top:3px}
.caplist{list-style:none;margin:0;padding:var(--s-1) var(--s-4) var(--s-3);display:grid;gap:var(--s-2)}
/* A LIST THAT SITS UNDER A SENTENCE, AT THE SENTENCE'S OWN LEFT EDGE. A browser
   indents a ul by 40px by default, which is a document convention and wrong
   inside a card: the bullet is the marker, the indent is a second marker saying
   the same thing, and it puts the items at an x nothing else on the card shares.
   The marker is kept and hung outside the text instead. */
/* padding-left is the hanging indent for the marker and NOT an indent of the
   block: .caplist already pays the card's 16px gutter in its own padding, so
   these two together used to put the text at 32px against a heading at 16.
   The marker now hangs in that 12px rather than the text being pushed past it. */
.caplist li{font-size:var(--fs-meta);color:var(--n-600);line-height:1.5;padding-left:var(--s-3);position:relative}
/* A hyphen, not an en dash. \2013 was the bullet glyph here, which put a dash
   this house does not use into the one list a buyer reads line by line. */
.caplist li::before{content:"-";position:absolute;left:0;top:0;color:var(--n-400)}
.capwhere{display:inline-block;margin-left:var(--s-2);font-family:var(--display);font-size:var(--fs-label);font-weight:600;
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--faint);border:1px solid var(--line);
  border-radius:4px;padding:1px var(--s-1);vertical-align:1px}
.ph2{margin:0 0 var(--s-1);font-family:var(--display);font-size:var(--fs-title);color:var(--navy)}
/* The contact card. One card, centred, sized so it reads from across a desk. */
.qrpanel{display:flex;justify-content:center}
.qrcard{width:100%;max-width:460px;display:flex;flex-direction:column;align-items:center;padding:var(--s-5) var(--s-4) var(--s-4)}
.qrcard:not(.card){padding:var(--s-2) 0 0}
.qrpanel.big .qrcard{max-width:560px;padding:var(--s-6) var(--s-5) var(--s-5)}
.qrpanel.big .qrname{font-size:var(--fs-page)}
.qrbox{background:#fff;border:1px solid var(--line);border-radius:var(--r-md);padding:var(--s-3);line-height:0}
.qrbox svg{display:block;max-width:100%;height:auto}
.qrmeta{text-align:center;margin-top:var(--s-4)}
.qrname{display:block;font-family:var(--display);font-size:var(--fs-title);font-weight:700;color:var(--navy);letter-spacing:var(--tr-tight)}
.qrhow{display:block;font-size:var(--fs-meta);color:var(--mut);margin-top:var(--s-2)}
.qracts{justify-content:center;margin-top:var(--s-4)}
/* An anchor styled as the ghost button it sits beside. Kept here rather than
   inline so they cannot drift apart. Not scoped to .sbtns: the same treatment
   is needed in the page head, where the onboard link opens a second tab. */
/* ---- THE LEFT EDGE IS THE CONTAINER'S, NEVER THE CALL SITE'S ---------------
 *
 * Every rule in this block replaces a `style="padding:..."` written into a
 * template literal in console.js. They are collected here rather than fixed
 * where they stood, because the fault is not the values. Most of them were 16,
 * which is correct. The fault is WHERE they were written: an inset in a style
 * attribute cannot be reached by a media query, cannot be retuned at a
 * breakpoint, and does not appear in this file at all, so the stylesheet says
 * the card gutter is 16 everywhere while eight blocks quietly decide for
 * themselves. Two of them had drifted off the scale to 11px and 18px, which is
 * the mechanical signature tokens.css already describes: somebody nudging a
 * number until it looked right, in the one place nobody would ever see it.
 *
 * THE RULE THIS BLOCK EXISTS TO MAKE ENFORCEABLE: a horizontal inset is either
 * the container's own gutter, spelled var(--s-N) in a stylesheet, or 0 because
 * an ancestor already paid it. checkInsets in scripts/check.mjs asserts it. */

/* A sentence directly above a table, inside a card. The table goes edge to edge
   so it can scroll, so this pays the gutter itself and the pair line up. */
.card>.tabletop{padding:var(--s-3) var(--s-4) 0;margin:0}

/* The in-card form error. Six call sites, one job, and they were written in two
   spellings: three in raw px and three in tokens, which is how you end up with
   a rule nobody can grep for. */
.card .formerr{padding:0 var(--s-4) var(--s-3);color:var(--status-alert-txt);font-size:var(--fs-meta)}

/* .repform already pays the gutter, so a .factline inside one must not pay it
   twice. Asked for by name in console.js, then written inline at both call
   sites instead. */
.repform .factline{padding:0}

/* Two card bodies whose vertical rhythm differs from the default. The gutter
   does not: that is the whole point of naming them. .roomy replaces an 18px
   bottom, which is on no scale in this product. */
.cbody.tight{padding:var(--s-3) var(--s-4) var(--s-1)}
.cbody.roomy{padding:var(--s-1) var(--s-4) var(--s-4)}

/* The Change button that follows a stated value on the Account card. Two call
   sites, both inline, both 8px. */
.hoursbtn.after{margin-left:var(--s-2)}

/* ONE MEASURE FOR THE GUIDE, AND THIS IS THE CALL SITE THAT ESCAPED IT. .gd-d
   declares 56ch for every description in the guide, with a comment saying it
   used to be three measures and was collapsed to one. Then one note rendered
   itself at 64ch from a style attribute, so that paragraph alone had a
   different right edge from its own siblings, invisible to a grep for 56ch.
   The class carries the spacing; the measure comes from .gd-d like the rest. */
.gd-d.gd-note{margin:var(--s-4) 0 0}

/* The Google mark inside the sign in button. Its own optical offset stays
   inline, because a 4px vertical nudge on one glyph is the shape of that mark
   rather than the space around a block, but the gap to the label is spacing. */
.gmark{margin-right:var(--s-2)}

/* A select that is deliberately smaller than a full width field, beside a
   button. It was padding:6px 10px, neither of which is a step. */
.inp.narrow{width:auto;font-size:var(--fs-body);padding:var(--s-1) var(--s-2)}

a.dl{text-decoration:none;display:inline-flex;align-items:center;padding:var(--s-1) var(--s-3);
  border:1px solid var(--line);border-radius:var(--r-sm);color:var(--n-600);
  font-family:var(--display);font-size:var(--fs-meta);font-weight:600;white-space:nowrap}
/* The page head copy of this link sits beside a 40px control and was hand
   rolled inline to match it, right down to a padding of 11px. The comment above
   says a.dl exists precisely so the page head does not do that. */
a.dl.tall{min-height:40px;color:var(--navy)}
a.dl:hover{border-color:var(--line-strong);color:var(--navy)}
a.dl:focus-visible{outline:none;box-shadow:var(--focus-ring)}
/* Required marker. A word, not an asterisk: an asterisk needs a legend and the
   legend is always somewhere else on the page. */
.req{margin-left:var(--s-1);font-family:var(--sans);font-size:var(--fs-label);font-weight:600;letter-spacing:var(--tr-label);
  text-transform:uppercase;color:var(--brand-solid)}
.obtrial{display:block;margin-top:var(--s-1);font-size:var(--fs-meta);color:var(--n-600);text-transform:none;letter-spacing:normal}
.obtrial b{color:var(--navy);font-weight:600}
/* Go live. A list, not cards: short lines that shrink to nothing as they are
   done, which is the only shape that reads as progress. */
/* THE HOLDER CARRIES THE GAP, AND ONLY WHILE IT HOLDS SOMETHING. On Team this
   card sat in a .stack, which gaps its children and hides the empty ones. The
   board is not a .stack, so the gap is declared here instead, at the same 14px
   .kpis and the band card already use between themselves. :not(:empty) is what
   keeps a finished account from carrying 14px of nothing above its board. */
#golive:not(:empty){margin:0 0 var(--s-3)}
.golive .glist{list-style:none;margin:0;padding:var(--s-1) var(--s-4) var(--s-3);display:grid;gap:2px}
.golive .glist li{display:grid;grid-template-columns:20px 1fr auto;gap:var(--s-2);align-items:center;
  padding:var(--s-2) 0;border-bottom:1px solid var(--n-50);font-size:var(--fs-body);color:var(--ink)}
.golive .glist li:last-child{border-bottom:0}
.golive .gtick{font-size:var(--fs-meta);font-weight:700;color:var(--status-active-txt);text-align:center}
.golive .glist li:not(.on) .gtick::before{content:"";display:inline-block;width:11px;height:11px;
  border:1.5px solid var(--n-400);border-radius:50%}
.golive .glist li.on .gt{color:var(--mut)}
/* ---- Setup: collapsed, and gated -------------------------------------------
 * The card is a <details> now, which is the disclosure pattern this file already
 * uses for the developer blocks, so it needs no new component and no new state.
 * open is set from the data on every paint: shut when nothing is outstanding,
 * open again by itself if a line later becomes false. */
.golive>summary{cursor:pointer;list-style:none}
.golive>summary::-webkit-details-marker{display:none}
/* The chevron IS the marker, and it turns. Drawn on the summary rather than
   imported, so it needs no icon set and no network request. */
.golive>summary::after{content:"";flex:none;width:8px;height:8px;margin-left:var(--s-2);
  border-right:2px solid var(--mut);border-bottom:2px solid var(--mut);
  transform:rotate(45deg) translate(-2px,-2px);transition:transform 140ms ease-out}
.golive[open]>summary::after{transform:rotate(-135deg) translate(-2px,-2px)}
.golive>summary:hover::after{border-color:var(--navy)}
.golive>summary:focus-visible{outline:2px solid var(--navy);outline-offset:-2px}
/* The heading and its infotip, so the chevron and the score can still sit at the
   far end of the summary row. */
.golive .gsum{display:flex;align-items:center;gap:var(--s-1);min-width:0}
.golive .gsum h2{font-family:var(--display);font-size:var(--fs-title);font-weight:var(--fw-semi);
  margin:0;color:var(--navy);letter-spacing:var(--tr-tight);line-height:var(--lh-tight)}
.golive>summary .sub{margin-left:auto}
/* A GATED LINE IS GREYED AND NAMES ITS PREREQUISITE. Not hidden: somebody needs
   to see that the step exists and why it is not available yet, or the list looks
   shorter than the job. No action button, because its action would land
   somewhere that cannot be used. */
.golive .glist li.gated .gt{color:var(--faint)}
.golive .glist li.gated .gtick::before{opacity:.45}
.golive .gneed{display:block;font-size:var(--fs-meta);color:var(--faint);margin-top:1px}
@media(prefers-reduced-motion:reduce){ .golive>summary::after{transition:none} }
.acctpick{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--s-2);margin-top:var(--s-3)}
/* An operable edge, so --line-strong. These are the account picker cards a
   super clicks to choose a client, and the plan cards on Onboard a client. One
   card shape, shared by selector, so the two cannot drift apart. */
.acctpick button,.plancards button{display:flex;flex-direction:column;align-items:flex-start;gap:2px;background:var(--card);color:var(--navy);border:1px solid var(--line-strong);border-radius:var(--r-md);padding:var(--s-3);cursor:pointer;text-align:left}
/* BORDER, NOT A LIFT. A resting card that rises under the cursor is the
   elevation idiom this system does not use anywhere else: the only shadows kept
   are on things that genuinely float, a panel, a modal, a toast and the bar over
   a scrolling claim page. The border colour already changes here and says the
   same thing for nothing. */
.acctpick button:hover,.plancards button:hover{border-color:var(--navy)}
.acctpick .an,.plancards .an{font-family:var(--display);font-weight:var(--fw-bold);font-size:var(--fs-body)}
/* A FIXED WIDTH, SO THE PLAN GROUP STOPS SETTING THE WIDTH OF ITS ROW. Two
   columns whatever the plan count, which wraps a fourth card under the third
   and leaves the starting credits control beside the group rather than adrift
   at the far side of the card. max-width is the narrow window: a fixed width
   inside a grid track that can shrink is what pushes a card past its parent. */
.plancards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-2);width:360px;max-width:100%}
/* Chosen is the panel's own selected treatment, an inset rule on the tint, and
   it reads at the same strength as the pressed segment beside it. */
.plancards button[aria-pressed=true]{background:var(--n-50);border-color:var(--navy);box-shadow:inset 0 0 0 1px var(--navy)}

/* ---- roadmap ---------------------------------------------------------------
 * One board of lanes. Live today at the left, then a lane per sprint, then
 * Later, and the board is the only place anything is edited.
 *
 * WHAT USED TO BE HERE. A second view, a timeline with themes down the side and
 * sprints across the top, plus the styles that drew a date range, a NOW badge
 * and a striped capacity bar on every sprint header. All of it was drawn from
 * sprint dates and story points, both of which the page no longer holds, so
 * .rmtl, .rmtlg, .rmweeks, .rmchip, .rmnow, .rmdate, .rmis, .rmcap, .rmcapn and
 * .rmpts went with them. A sprint is now a name, a goal and an order.
 *
 * NO NEW COLOURS. Eight themes would be eight hues, and eight hues is a second
 * palette competing with the one the product already has. Theme is set as a
 * micro label, status carries the only colour, and it uses the four status
 * tokens the board already uses for leads. */
.rmbar{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin:0 0 var(--s-3)}
.rmbar .sp{flex:1 1 auto}
/* The lane strip. Horizontal scroll inside its own container, never the page:
   min-width:0 on the track is what keeps a wide board from setting the width of
   the document. */
.rmboard{display:flex;gap:var(--s-3);overflow-x:auto;padding:2px 2px var(--s-2);min-width:0;
  scroll-snap-type:x proximity}
.rmlane{flex:0 0 272px;max-width:272px;display:flex;flex-direction:column;min-width:0;
  background:var(--n-25);border:1px solid var(--line);border-radius:var(--r-md);scroll-snap-align:start}
/* What the product does today is a lane like any other, at the far left, on a
   white ground so it reads as settled rather than as work. */
.rmlane.done{background:var(--card)}
.rmlane.over{border-color:var(--navy);background:var(--n-50)}
.rmlhead{padding:var(--s-3) var(--s-3) var(--s-2);border-bottom:1px solid var(--line)}
.rmlname{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2)}
.rmlname b,.rmlname .rmname{font-family:var(--display);font-size:var(--fs-body);font-weight:var(--fw-semi);color:var(--navy);
  letter-spacing:var(--tr-tight)}
/* The sprint name is the way into the sprint's own settings. Set as the heading
   it already was, so the header gains a control without gaining an element. */
.rmlname .rmname{background:none;border:0;padding:0;cursor:pointer;text-align:left;line-height:var(--lh-tight)}
.rmlname .rmname:hover{text-decoration:underline}
.rmlname .rmname:focus-visible{outline:2px solid var(--navy);outline-offset:2px;border-radius:2px}
.rmlname .n{font-size:var(--fs-label);color:var(--faint);font-variant-numeric:tabular-nums;white-space:nowrap}
.rmgoal{font-size:var(--fs-meta);color:var(--mut);line-height:var(--lh-snug);margin-top:var(--s-1)}
.rmitems{padding:var(--s-2);display:grid;gap:var(--s-2);align-content:start;flex:1 1 auto;min-height:56px}
.rmcard{background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);padding:var(--s-2) var(--s-2);
  cursor:grab;text-align:left;width:100%;display:block;font-family:var(--sans);color:var(--ink)}
.rmcard:hover{border-color:var(--line-strong)}
/* The card is the only keyboard route into the editor, so it keeps the app's
   real 2px outline. A border colour swap plus the focus glow was the first
   version and it is close to invisible on white. */
.rmcard:focus-visible{outline:2px solid var(--navy);outline-offset:1px}
.rmcard.dragging{opacity:.4}
/* Where the card will land. A line above the card being hovered, not a gap that
   opens: a gap moves every other card and the one you are aiming at walks away
   from the cursor. */
.rmcard.dropat{box-shadow:0 -2px 0 0 var(--navy)}
.rmcard .rmt{font-size:var(--fs-body);font-weight:var(--fw-semi);color:var(--navy);line-height:var(--lh-snug);
  letter-spacing:var(--tr-tight);display:block}
.rmlane.done .rmcard .rmt{font-weight:var(--fw-med);color:var(--ink)}
.rmcard .rmd{font-size:var(--fs-meta);color:var(--mut);line-height:var(--lh-snug);margin-top:3px;
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical}
.rmmeta{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-2)}
.rmtheme{font-family:var(--display);font-size:var(--fs-label);font-weight:var(--fw-semi);letter-spacing:var(--tr-label);
  text-transform:uppercase;color:var(--faint)}
/* The count, and never a word of the comment itself. It is drawn only when there
   is at least one, because "0 comments" on forty five cards is forty five lines
   saying nothing. */
.rmcn{font-size:var(--fs-label);color:var(--faint);font-variant-numeric:tabular-nums}
/* NOT styled as a link. It was --blue-d with a hover underline, which is this
   app's anchor treatment, and clicking it opens the editor rather than Jira. An
   anchor cannot live here anyway: the card is itself a button. */
.rmjira{font-family:var(--display);font-size:var(--fs-label);font-weight:var(--fw-semi);color:var(--mut);
  letter-spacing:var(--tr-label)}
/* A dependency is only worth a line on the card when it is a problem: waiting
   on something that is not shipped and is not scheduled before this. */
.rmwait{display:block;margin-top:var(--s-1);font-size:var(--fs-meta);line-height:var(--lh-snug);
  color:var(--status-alert-txt)}
.rmwait.ok{color:var(--mut)}
/* Solid, not dashed. tokens.css reserves dashed for test data and says so:
   .tag-test and tr.testrow are the only dashed and striped things in the system
   precisely so that neither can ever be read as a status. A second dashed thing
   spends that. */
.rmnew{border:1px solid var(--line-strong);background:none;color:var(--mut);border-radius:var(--r-sm);
  padding:var(--s-2);font-family:var(--sans);font-size:var(--fs-meta);width:100%;cursor:pointer}
.rmnew:hover{border-color:var(--navy);color:var(--navy);background:var(--n-0)}
/* A TRANSPARENT BORDER, SO IT LANDS WHERE A REAL CARD'S TEXT LANDS. .rmcard is
   8px of box padding inside a 1px border inside .rmitems' 8px, so its text sits
   at 17. This was padding:var(--s-2) 2px, which put "Nothing here yet." at 10,
   a third x in a 272px lane whose header is at 12. The 2px was also a misuse of
   the 1/2/3px exemption in tokens.css, which is for the shape of a control and
   not for the space around one. */
.rmempty{font-size:var(--fs-meta);color:var(--faint);
  border:1px solid transparent;padding:var(--s-2)}

/* ---- the item editor ------------------------------------------------------ */
.modal .mc.wide{max-width:580px;max-height:88vh;overflow-y:auto}
.rmform{display:grid;gap:var(--s-3)}
.rmform .two{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-3)}
/* --line-strong, AND tokens.css SAID SO IN CAPITALS. Its own comment reads
   "never the boundary of a form control" against --line at 1.35:1, and these
   two textareas used it anyway, which is the self-contradiction pattern this
   pass exists to close. */
.rmform textarea,.rmcm textarea{width:100%;font-family:var(--sans);padding:var(--s-2) var(--s-3);line-height:var(--lh-body);
  border:1px solid var(--line-strong);border-radius:var(--r-sm);color:var(--ink);background:#fff;resize:vertical;min-height:76px}
.rmform textarea:focus,.rmcm textarea:focus{outline:none;border-color:var(--navy);box-shadow:var(--focus-ring)}
.rmdeps{border:1px solid var(--line);border-radius:var(--r-sm);max-height:150px;overflow-y:auto;padding:var(--s-2) var(--s-2)}
.rmdeps label{display:flex;align-items:flex-start;gap:var(--s-2);font-family:var(--sans);font-size:var(--fs-meta);
  font-weight:var(--fw-body);text-transform:none;letter-spacing:normal;color:var(--ink);margin:0 0 var(--s-1);
  line-height:var(--lh-snug);cursor:pointer}
.rmdeps label:last-child{margin-bottom:0}
.rmdeps .gp{font-family:var(--display);font-size:var(--fs-label);font-weight:var(--fw-semi);letter-spacing:var(--tr-label);
  text-transform:uppercase;color:var(--faint);margin:var(--s-2) 0 var(--s-1)}
.rmdeps .gp:first-child{margin-top:0}
.rmacts{display:flex;gap:var(--s-2);align-items:center;margin-top:var(--s-3)}
.rmacts .sp{flex:1 1 auto}
.rmerr{font-size:var(--fs-meta);color:var(--status-alert-txt);min-height:1em}

/* ---- comments on an item ---------------------------------------------------
 * In the editor, under the form, because a comment is about one card and there
 * is nowhere else on this page for it to go: a lane is 272px wide and a
 * discussion is not a thing anybody reads at that width. The card carries the
 * count and nothing else, which is enough to know there is something to open.
 *
 * NO NEW COLOURS HERE EITHER, the same rule the rest of this page follows. A
 * comment is a name, a time and a paragraph, so it is set on the type scale and
 * marked with the one 2px rule down its left edge. Avatars, threads and reply
 * chains were all considered and are all absent: three people share this board.
 *
 * THE BODY IS THE HIGHEST RISK STRING ON THE PAGE and two separate things guard
 * it. The escaping is in the JavaScript, where it goes through h() into a text
 * node and never into an attribute. This is the other half: pre-wrap so the line
 * breaks somebody typed survive, and overflow-wrap so a single 2000 character
 * word cannot set the width of the modal and push Save off the screen.
 */
.rmcm{margin-top:var(--s-4);border-top:1px solid var(--line);padding-top:var(--s-3)}
.rmcmh{font-family:var(--display);font-size:var(--fs-label);font-weight:var(--fw-semi);letter-spacing:var(--tr-label);
  text-transform:uppercase;color:var(--faint);margin:0 0 var(--s-2)}
/* Scrolls inside itself at the same height as the dependency picker above it,
   so a card with forty comments does not turn this modal into a page. */
.rmcml{display:grid;gap:var(--s-3);max-height:220px;overflow-y:auto;margin-bottom:var(--s-3)}
.rmc{border-left:2px solid var(--line);padding-left:var(--s-2)}
.rmch{display:flex;align-items:baseline;gap:var(--s-2);flex-wrap:wrap}
.rmcw{font-family:var(--display);font-size:var(--fs-meta);font-weight:var(--fw-semi);color:var(--navy)}
.rmct{font-size:var(--fs-label);color:var(--faint);font-variant-numeric:tabular-nums}
.rmcb{font-size:var(--fs-meta);color:var(--ink);line-height:var(--lh-snug);margin-top:3px;
  white-space:pre-wrap;overflow-wrap:anywhere}
/* Only ever drawn on your own. A quiet text control rather than a red outlined
   button: a discussion you wrote all of would otherwise be a column of red down
   the right hand side, which states the wrong thing loudly. */
.rmcdel{background:none;border:0;padding:0;margin-left:auto;font-family:var(--sans);
  font-size:var(--fs-label);color:var(--mut);cursor:pointer}
.rmcdel:hover{background:none;color:var(--status-alert-txt);text-decoration:underline}
/* Armed. It says what the second click does rather than only looking different,
   because a label that has not changed reads as a first click that did nothing. */
.rmcdel[data-armed="1"]{color:var(--status-alert-txt);font-weight:var(--fw-semi)}
.rmcdel:focus-visible{outline:2px solid var(--navy);outline-offset:2px;border-radius:2px}
/* Post is right aligned so it sits over Save rather than beside the textarea,
   and it is ghost, not filled: the modal already spends its one filled button
   on Save and a second one would make the two look like a choice. */
.rmcpost{display:flex;justify-content:flex-end;margin-top:var(--s-2)}
/* A destructive button that has been armed. It fills, so the second click never
   looks like a repeat of a first one that appeared to do nothing. */
button.danger.armed{background:var(--status-alert-bg);border-color:var(--status-alert-txt);font-weight:var(--fw-bold)}
@media(max-width:560px){
  .rmlane{flex-basis:84vw;max-width:84vw}
  .rmform .two{grid-template-columns:1fr}
}

/* ---- integrations -----------------------------------------------------------
 *
 * ONE LIST, GROUPED BY STATE, AND THE GROUP LABEL IS THE STATUS. Connected,
 * then available to connect, then coming soon. A grid of same size tiles was
 * here before and it made every integration look like every other one: a tile
 * could not say "this one is live and quiet" without repeating the word
 * connected on six tiles at once. A grouped list says it once, in the group
 * label, so a row carries only what is true of that row and the whole page
 * reads in one pass and collapses to nine lines.
 *
 * NOTHING NESTS. A row sits on the card's own surface, its detail opens
 * underneath it on the same surface, and there is never a card inside a card.
 *
 * Sized to survive a 360px phone: every grid track is minmax(0,1fr) or a fixed
 * pixel column, everything that can hold something wider than the screen (a
 * URL, a payload, a table) scrolls inside itself, and nothing here is set with
 * an inline style, because an inline style beats the media queries below.
 */
.intsec+.intsec{margin-top:var(--s-5)}
/* More space above the group label than below it: the label belongs to the list
   under it, not to the list above it. */
/* THE SECTION HEADING, AND IT USED TO BE SMALLER THAN THE CARDS IT CONTAINS.
   It was --fs-label uppercase in --faint, 11px, sitting above card titles at
   18px. A container that announces itself more quietly than its contents is not
   a hierarchy, and Integrations had that on every section.

   THE SIZE ALONE COULD NOT FIX IT, WHICH IS WHY THIS LOOKS LIKE MORE THAN A
   SIZE CHANGE. 24px collides with the page title and the scale has no free step
   between 18 and 24, so at 18px this is the same size as the card titles below
   it. The hierarchy therefore comes off a different axis: a full width hairline
   and 32px of air above it. A card title never has a rule above it and always
   sits inside a card, so the two never read as the same level despite sharing a
   size. Drawn in deliverables/ux-surfaces-mock.html as .sechead and copied from
   there rather than reinterpreted.

   The uppercase and the letter-spacing both go. A 12.5px uppercase kicker is a
   format that appears nowhere else in this product, and a format used once is a
   thing a reader has to learn for one screen. */
/* A WRAPPER, NOT THE HEADING ITSELF, because the section i-button is a sibling
   of the h2 and not inside it. A button inside a heading joins that heading's
   accessible name, so a screen reader reads "Outgoing About your CRM key" as
   the heading text. .ctitle is the house pattern for the same reason. The rule
   and the spacing therefore live on the wrapper, which is the element that
   spans the section, and the type lives on the h2 inside it. */
.intgrp{display:flex;align-items:center;gap:var(--s-1);
  margin:var(--s-6) 0 var(--s-3);padding-top:var(--s-4);border-top:1px solid var(--line)}
.intgrp>h2{font-family:var(--display);font-size:var(--fs-title);font-weight:var(--fw-semi);
  color:var(--navy);letter-spacing:var(--tr-tight);line-height:var(--lh-tight);margin:0}
/* No rule above the first section: it would draw a line immediately under the
   page head, which reads as a border on the page rather than as a divider.

   :first-child WAS WRONG AND SHIPPED WRONG. Every .intgrp is the first child of
   its own <section class="intsec">, so the guard matched every heading on the
   page and removed the hairline from all of them, which is the one thing F5 was
   for. The guard has to name the first SECTION, not the first child. Caught on
   the live page rather than by any check, because nothing here can assert what
   a selector matched. */
.intsec:first-of-type>.intgrp{margin-top:0;padding-top:0;border-top:0}
/* THE SECTION INTRO, AND IT CARRIES NO MEASURE OF ITS OWN. IT TAKES THE CARD'S.
 *
 * This was capped at 70ch, which is 552px of 12.5px type, sitting between a
 * heading that spans the section and a card that is 1233px wide on a desk. The
 * note and the card are siblings, so their left edges lined up and their right
 * edges did not, and the Outgoing sentence fell to four short lines against a
 * mostly empty right half. It read as an indented column. Nothing was indented:
 * the right edge was pulled in, and the eye cannot tell those two apart.
 *
 * THE MEASURE IS NOT DELETED, IT IS HANDED BACK. .factline already sets
 * min(100%,128ch), and tokens.css argues that number at length: wide enough that
 * a shortened intro finishes on one line, still biting on anything genuinely
 * long, and never wider than its container, so a narrow screen gets the card's
 * width to the pixel and the two edges stay together all the way down. The
 * .intexp .factline rule below removed exactly this override for exactly this
 * reason, and .intnote is the last place it survived: two paragraphs of the same
 * style in the same section were being set to two different measures, and the
 * narrower one was the one outside the card, where nothing was constraining it.
 *
 * Do not centre it instead. The uppercase group label above it and the card
 * below it are both hard left, so a centred note is inset on both sides and
 * floating between two things that are not. */
.intnote{margin:0 0 var(--s-2)}
.intitem{border-bottom:1px solid var(--line)}
.intitem:last-child{border-bottom:0}
/* The row. Name, then state, then activity, with the chevron in a fixed column
   of its own so it cannot move when the middle wraps. */
.introw{display:grid;grid-template-columns:minmax(0,1fr) 10px;gap:0 var(--s-3);align-items:center;
  width:100%;text-align:left;background:var(--card);color:var(--ink);border:0;border-radius:0;
  font-family:var(--sans);font-size:var(--fs-body);padding:var(--s-3) var(--s-4);cursor:pointer;min-width:0}
.introw:hover{background:var(--n-25)}
.introw:focus-visible{outline:2px solid var(--navy);outline-offset:-2px}
.introw .rmain{display:flex;align-items:center;gap:var(--s-1) var(--s-3);flex-wrap:wrap;min-width:0}
.introw .rn{flex:1 1 auto;min-width:0;font-family:var(--display);font-size:var(--fs-body);
  font-weight:var(--fw-semi);color:var(--navy);letter-spacing:var(--tr-tight);line-height:var(--lh-snug)}
.introw .rv{flex:none;font-size:var(--fs-meta);color:var(--mut);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.introw .errn{color:var(--status-alert-txt);font-weight:var(--fw-semi)}
.introw .chev{color:var(--n-400);transition:transform 160ms ease-out}
.introw[aria-expanded=true] .chev{transform:rotate(180deg);color:var(--navy)}
/* A planned integration. A div and never a button: a control that cannot be
   operated is a broken control, and this is a statement about the roadmap. The
   group label above it is what says it is not available yet, so the row is a
   name and nothing else. Denser than an operable row as well as quieter: seven
   roadmap names at the height of a row you can act on would be the largest thing
   on a page whose job is the four above them. */
.introw.soon{cursor:default;padding-top:var(--s-2);padding-bottom:var(--s-2)}
.introw.soon .rn{color:var(--n-500);font-weight:var(--fw-med)}
@media(max-width:560px){
  /* Name on its own line, state and figures under it, chevron still in its own
     column. Ellipsising an integration's name is never the right answer. */
  .introw .rn{flex:1 1 100%}
}
/* THE ONE AUTHORED MOTION MOMENT ON THIS PAGE. The row is already visible, so
   opening it eases the panel's own grid track from 0fr to 1fr and nothing
   enters. A pixel height would have to be measured, and would be wrong the
   moment the delivery log arrives; a track fraction grows to whatever the panel
   turns out to hold. A browser that cannot interpolate a track size jumps
   instead of easing, which is the right degradation: the panel is open either
   way. visibility is what keeps a closed panel out of the tab order. */
.intexp{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows 260ms cubic-bezier(.16,1,.3,1)}
.intexp>.in{overflow:hidden;min-height:0;visibility:hidden;
  transition:visibility 0s linear 260ms;padding:2px var(--s-4) var(--s-4)}
.intitem.open .intexp{grid-template-rows:1fr}
.intitem.open .intexp>.in{visibility:visible;transition:visibility 0s}
@media(prefers-reduced-motion:reduce){
  .intexp,.intexp>.in,.introw .chev{transition:none}
}
/* .card .factline carries the card's own 16px gutter, and inside a panel that
   is already padded it reads as a stray indent. Reset once here rather than
   with an inline style on every line. */
/* NO max-width HERE, AND THAT IS THE FIX RATHER THAN THE OMISSION.
 *
 * This capped every panel intro at 70ch, which is 552px, inside a card that is
 * 1233px wide on a desk. The heading directly above it spans the full width, so
 * a fifteen word sentence broke into two short ragged lines occupying 45% of the
 * card and read as an indented column against its own siblings. Chirag called it
 * left indent crap and he was reading it correctly: nothing is indented, the
 * right edge is pulled in, and the eye cannot tell those apart.
 *
 * 70ch is the classic reading measure and it is the wrong tool for this text.
 * tokens.css argues the whole case at length on .factline itself: these are one
 * and two sentence intros, a measure is meant to be invisible, and a break the
 * reader can see no reason for is worse than a long line because the eye stops
 * and looks for the cause. It settled on min(100%, 128ch) precisely so a
 * shortened intro finishes on one line, and this override reintroduced the
 * defect that reasoning was written to remove.
 *
 * So the cap comes off and the token's own applies. Padding and margin stay:
 * .intexp pays the gutter, so the paragraph must not pay it twice. */
.intexp .factline{padding:0;margin:0 0 var(--s-3)}
.intexp .factline.intsub{margin:var(--s-2) 0 0}
.intexp .facts{border-top:1px solid var(--line)}
.intexp .facts .frow{padding:var(--s-2) 0}
.intexp .facts .frow .pill,.intexp .facts .frow .pillbtn{vertical-align:1px}
.intexp .sect:last-child{margin-bottom:0}
/* The same reset .csect .repform pays, for the same reason. A panel already
   carries its own 16px gutter, so the form's own padding reads as an indent and
   its top border draws a line across the middle of an open panel. The outgoing
   rows put a paste-your-key form inside a panel, which is the first time these
   two components have met. */
.intexp .repform{padding:0;border-top:0}
/* THE HEADING ROW WITH A CONTROL ON THE RIGHT. It was scoped to .logsect, which
   was correct while the delivery log was the only section shaped this way. The
   field mapping section is the second, so the rule moves off the one component
   that happened to own it. Both selectors are kept: .logsect .lhead was in the
   cascade before .lhead existed and a bare rename would rely on nothing else
   having leaned on the more specific one. */
.lhead,
.logsect .lhead{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);
  flex-wrap:wrap;margin:0 0 var(--s-2)}
.lhead h3,
.logsect .lhead h3{margin:0}

/* A MAPPING THAT HAS STOPPED MATCHING, WHICH MEANS LEADS ARE ARRIVING INCOMPLETE
   RIGHT NOW. It is the only thing on that panel that is actively costing
   somebody something, so it is the alert colour rather than the notice colour,
   and it sits above the table rather than tinting a cell: a person scanning
   thirteen rows for a tinted cell is a person who does not see it. The row tint
   is the second half of the same signal and is deliberately much fainter, so it
   guides the eye once the sentence has already been read. */
.warnline{background:var(--status-alert-bg);color:var(--status-alert-txt);
  border:1px solid var(--status-alert-line);border-radius:var(--r-sm);
  padding:var(--s-3);margin:0 0 var(--s-3)}
.warnline b{color:inherit}
tr.staleRow>td{background:var(--status-alert-bg)}
/* The select in the mapping table. Full width of its cell so the key names,
   which are long and unfamiliar, are readable without truncation. */
[data-mapfield]{width:100%;min-width:11rem;max-width:22rem}
.intform{display:grid;gap:var(--s-3);min-width:0}
.intform>*{min-width:0}
.intform .two{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s-3)}
.intacts{display:flex;gap:var(--s-2);align-items:center;margin-top:var(--s-4);flex-wrap:wrap}
.intacts .sp{flex:1 1 auto}
.interr{font-size:var(--fs-meta);color:var(--status-alert-txt);min-height:1em;margin:0}
/* THE ALERTS SWITCH IN THE FORM, AND WHY IT IS A PANEL RATHER THAN A ROW. Off is
   the default on every source and it is the state a real client's source is
   connected in, so it has to read as off from across a desk. The position of a
   32px control cannot carry that on its own, so the row states what is and is
   not being sent and changes colour when it changes meaning. */
.alertsw{border:1px solid var(--line);border-radius:var(--r-sm);padding:var(--s-3) var(--s-3)}
.alertsw.on{border-color:var(--status-active-line);background:var(--status-active-bg)}
.alertwhat{flex:1 0 100%;font-size:var(--fs-meta);color:var(--mut);line-height:var(--lh-body)}
.alertsw.on .alertwhat{color:var(--status-active-txt)}
/* THE ONE CROSS-PAGE BANNER, plan 1.6. The board, Team, Integrations and the
   demo console each print it from the same string and the same class, so a
   second notice style is never a temptation the next screen reaches for.
   Amber, not red: a pause is a deliberate choice, not a fault. */
.pausebar{margin:0 0 var(--s-4);padding:var(--s-3) var(--s-4);border-radius:var(--r-sm);
  border:1px solid var(--status-new-line);background:var(--status-new-bg);
  color:var(--status-new-txt);font-size:var(--fs-body);line-height:var(--lh-body)}
/* THE WIDGET PICKER WAS HERE AND IS GONE, 31 July 2026. It listed every widget
   in the business by volume, with the client each one is taken by. That is the
   whole book of business on a screen an operator opens in front of a customer.
   The widget ID is typed and nothing else. */
/* A payload or a command. Monospace because it is genuinely code, and it scrolls
   in both directions inside its own box: a single unbroken 900 character line
   arrives from the open internet regularly and it must not widen the page. */
.raw{margin:0;width:100%;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:var(--fs-meta);line-height:var(--lh-snug);color:var(--n-700);background:var(--n-25);
  border:1px solid var(--line);border-radius:var(--r-sm);padding:var(--s-2) var(--s-3);overflow:auto;
  max-height:260px;white-space:pre;min-width:0}
.rawwrap{display:grid;gap:var(--s-1);justify-items:start;min-width:0}
.copyrow{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--s-2);align-items:center;min-width:0}
/* Hide, directly under the revealed URL rather than at the foot of the panel,
   because the developer material below it runs to several screens. */
.revacts{display:flex;margin-top:var(--s-2)}
/* The slot sits under a heading in an incoming panel and inside a facts row on a
   chat channel. A little air above it either way, so the button is not welded to
   the sentence that explains what it is about to show. */
.reveal{margin-top:var(--s-2)}
/* .clinkslot was here: the reveal slot as it sat in the Team account card's own
   flow rather than inside an integration panel. The connect link is on
   Integrations only now, so the slot is only ever inside a panel and this rule
   styled nothing. */
/* THE FIELDS WE ACCEPT, IN THE WORDS SOMEBODY BUYING THIS WOULD USE. Eight plain
   names, the one required marked once. The exact keys and every spelling we
   accept are a schema, and a schema is developer material: it lives behind the
   disclosure. */
.fieldlist{list-style:none;margin:0;padding:0;min-width:0;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));
  gap:var(--s-1) var(--s-4);max-width:520px;font-size:var(--fs-body);color:var(--ink)}
.fieldlist li{min-width:0}
.rq{font-family:var(--display);font-size:var(--fs-label);font-weight:var(--fw-semi);
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--brand-solid);white-space:nowrap}
/* The alias table. An alias list is a long unbroken run of monospace, so the
   table scrolls inside .tblwrap rather than widening the panel. */
.pc{width:100%;border-collapse:collapse;font-size:var(--fs-meta)}
.pc th,.pc td{text-align:left;padding:var(--s-1) var(--s-3) var(--s-1) 0;border-bottom:1px solid var(--line);
  vertical-align:top;line-height:var(--lh-snug)}
.pc th{font-family:var(--display);font-size:var(--fs-label);text-transform:uppercase;
  letter-spacing:var(--tr-label);color:var(--faint);font-weight:var(--fw-semi);white-space:nowrap}
.pc tr:last-child td{border-bottom:0}
.pc td.k{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:var(--navy);white-space:nowrap}
.pc td.al{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:var(--mut)}
/* DEVELOPER MATERIAL, FOLDED AWAY. A cURL command and a list of accepted field
   names are the right answer for one reader and a wall of code for the other,
   and the other one is the person deciding whether to buy this. Native details,
   so it opens with a keyboard and needs no script. */
details.dev{border:1px solid var(--line);border-radius:var(--r-sm);background:var(--n-25);min-width:0}
details.dev>summary{font-family:var(--display);font-size:var(--fs-meta);font-weight:var(--fw-semi);
  color:var(--navy);padding:var(--s-2) var(--s-3);cursor:pointer;list-style:none;display:flex;align-items:center;gap:var(--s-2)}
details.dev>summary::-webkit-details-marker{display:none}
details.dev>summary::before{content:"";width:0;height:0;flex:none;
  border-left:5px solid currentColor;border-top:4px solid transparent;border-bottom:4px solid transparent}
details.dev[open]>summary::before{transform:rotate(90deg)}
details.dev>summary:focus-visible{outline:2px solid var(--navy);outline-offset:-2px;border-radius:var(--r-sm)}
details.dev .devbody{padding:2px var(--s-3) var(--s-3);border-top:1px solid var(--line);min-width:0}
/* .outkey WAS HERE AND WENT WITH THE PANEL IT DREW, B3. Its premise was that
   "a log whose rows read no_phone and nothing else is a log somebody has to be
   taught to read". That premise stopped being true: the Outcome cell renders
   the plain word and keeps the raw enum on the hover, and dcp.source_deliveries
   carries a detail on every row, checked in production and empty on none of 60.
   The log explains itself, so the key explaining the log had nothing left to do.
   Its own b rule set the plain word in monospace, which is how a glossary meant
   for clients ended up looking like a developer reference. */
/* The alerts control, beside the word Alerts. Off is a sentence elsewhere on the
   page and one word here, so a row of them scans. */
.pillbtn.alerts{white-space:nowrap}
tr.openrow td{background:var(--n-50)}
/* A connection row is reachable with Tab, so it takes the same 2px navy ring as
   every other focusable on this page. Without it the browser draws its own
   default, which is the one focus state on the screen that does not match. */
tr[data-conn]:focus-visible{outline:2px solid var(--navy);outline-offset:-2px}
td .errn{color:var(--status-alert-txt);font-weight:var(--fw-semi)}
/* ---- outgoing ----------------------------------------------------------------
   The client's own CRM and their own chat space. These rules were written when
   this was a page of its own built out of .csect blocks. It is the bottom half
   of Integrations now and its rows are accordion panels, so .csect is left
   carrying the test lead composer alone. The rule stays because that card still
   needs it: a .csect already pays the 16px gutter, so the facts rows inside one
   drop theirs rather than indenting twice against the heading above them. */
.csect .facts .frow{padding:var(--s-2) 0}
/* A fingerprint is eight characters somebody reads against a key they are
   holding, so it is set like the thing it stands for. */
.fpr{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:var(--n-700)}
/* SOMEBODY ELSE'S ERROR, MARKED AS THEIRS. last_error is HubSpot's words or
   Slack's, and the fix for it is inside their system rather than ours, so it is
   given room to be read in full instead of being cut to a table cell. */
.connerr{font-size:var(--fs-meta);color:var(--status-alert-txt);background:var(--status-alert-bg);
  border-radius:var(--r-sm);padding:var(--s-2) var(--s-3);margin:var(--s-3) 0 0;line-height:var(--lh-body);
  max-width:var(--mw-read);overflow-wrap:anywhere}
/* The quoted line keeps the block's colour. The default --faint is a grey chosen
   against a card, and this block is not a card. */
.connerr .subline{color:var(--status-alert-txt)}
/* THE ANSWER TO "DOES THIS KEY ACTUALLY WORK". Three outcomes and three
   treatments, and the middle one is the one that matters: a key the CRM
   accepted, whose write permission we could not check. It is deliberately NOT
   green. Green for "we do not know" is how a console tells somebody their
   integration is fine on the morning it silently is not. */
.crmchk:empty{display:none}
.chkok,.chkpart{font-size:var(--fs-meta);border-radius:var(--r-sm);
  padding:var(--s-2) var(--s-3);margin:var(--s-3) 0 0;line-height:var(--lh-body);max-width:var(--mw-read)}
.chkok{color:var(--status-active-txt);background:var(--status-active-bg)}
.chkpart{color:var(--status-new-txt);background:var(--status-new-bg)}
/* ---- who owns it once somebody claims, as a match up ------------------------
   A CONSULTANT'S NAME IS NOT A FIELD LABEL. Drawn as one it took the uppercase
   11px micro treatment, so the panel was a stack of shouted names over a stack
   of dropdowns and read as a form to fill in. The pair is the point: ours on
   the left at reading size, theirs opposite, the arrow between them. */
.crmmaphead,.crmmaprow{display:grid;grid-template-columns:minmax(0,1fr) var(--s-5) minmax(0,1fr);
  gap:var(--s-3);align-items:center}
.crmmaphead{padding-bottom:var(--s-2);font-family:var(--display);font-size:var(--fs-label);
  font-weight:var(--fw-semi);letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--faint)}
.crmmaprow{padding:var(--s-3) 0;border-top:1px solid var(--line)}
.crmmaprow label.crmmapname{font-family:var(--sans);font-size:var(--fs-body);font-weight:var(--fw-med);
  text-transform:none;letter-spacing:0;color:var(--ink);margin:0;overflow-wrap:anywhere}
/* Its own track, so it holds the middle as either name wraps. */
.crmmaparrow{text-align:center;color:var(--mut)}
.crmmapnote{display:block;font-size:var(--fs-meta);color:var(--mut);margin-top:var(--s-1)}
.crmmapnote:empty{display:none}
@media(max-width:720px){
  /* Stacked, the name sits directly above the control it points at, which is
     the arrow's whole job, and the column heads have nothing left to head. */
  .crmmaphead,.crmmaparrow{display:none}
  .crmmaprow{grid-template-columns:minmax(0,1fr);gap:var(--s-1)}
}
/* .intalso was the other name a vendor is sold under, set beside the vendor
   name in the connect form's heading. That heading is now "What to paste" and
   the other name is a .factline.intsub under what leaves here, so the rule had
   no element left to style. Recognising a row labelled Freshworks CRM still
   matters; it is done with a shared class now. */
@media(max-width:560px){
  .intform .two{grid-template-columns:minmax(0,1fr)}
}

/* ---- the setup guide -------------------------------------------------------
 * WHERE TO FIND A KEY, DRAWN RATHER THAN WRITTEN.
 *
 * Every one of these instructions used to be a single sentence naming four
 * menus in a row: "In HubSpot go to Settings, then Integrations, then Private
 * apps. Create a private app, tick write access...". That sentence is
 * thirty-eight words describing six separate physical actions, and it is read
 * by somebody who has our screen open, their CRM open, and no idea which of the
 * six they are currently on. Chirag's instruction was explicit: this is read by
 * people with a learning disability, so put the weight on visual dispersion of
 * information rather than on more text.
 *
 * So one action per row, a picture of the thing to look for, a number, and a
 * line down the page connecting each step to the next. The picture is the point:
 * "click your profile picture" is instant next to a drawn avatar and is a
 * sentence to parse without one.
 *
 * THE FIGURES ARE OF THE VENDOR'S SCREEN, NEVER OF OURS, which is the standing
 * rule from the design critique: a screenshot of our own UI inside our own UI is
 * decoration that rots on the next redesign. These are drawn shapes rather than
 * screenshots for the same reason, one step further: a vendor moving a button
 * invalidates a screenshot and leaves a drawn avatar still true.
 *
 * Nothing is carried by colour. Every step is a number, a shape and a sentence,
 * and the colour underneath them is the same on all of them. */
.gd{min-width:0}
/* ONE MEASURE FOR THE WHOLE GUIDE, AND IT USED TO BE THREE.
   The intro capped at 64ch, the step description at 56ch, and the step title at
   nothing at all. Inside a card near 1000px that put three different right edges
   in one block: a title running to about 680px above its own description
   stopping at 350px, with the intro ending somewhere else again. Nothing in it
   was wrong on its own and the block read as broken, because a reader takes the
   ragged right edge as the shape of the thing.

   56ch, which is the narrowest of the three, so no measure widens. Declared once
   here rather than on each element, for the same reason .cs and .factline were
   collapsed: three numbers doing one job is how they drift apart. */
.gd-lead,.gd-t,.gd-d{max-width:var(--mw-narrow)}
.gd-lead{font-size:var(--fs-body);color:var(--ink);line-height:var(--lh-body);margin:0 0 var(--s-4)}
.gd-steps{list-style:none;margin:0;padding:0;min-width:0}
.gd-step{display:grid;grid-template-columns:44px minmax(0,1fr);gap:0 var(--s-4);
  padding:0 0 var(--s-5);position:relative;min-width:0}
.gd-step:last-child{padding-bottom:0}
.gd-fig{width:44px;height:44px;border-radius:var(--r-sm);background:var(--n-50);
  border:1px solid var(--n-200);color:var(--navy);
  display:flex;align-items:center;justify-content:center;position:relative;flex:none}
/* THE LINE IS THE ARROW. It runs from the bottom of one tile to the top of the
   next, so the eye is carried down the sequence instead of having to work out
   that the rows are ordered. The chevron at its foot is what makes it a
   direction rather than a rule: without it this reads as a table border. */
.gd-step:not(:last-child) .gd-fig::after{content:"";position:absolute;left:50%;top:44px;
  width:2px;height:calc(100% + var(--s-5) - 44px);margin-left:-1px;background:var(--n-200)}
.gd-step:not(:last-child) .gd-fig::before{content:"";position:absolute;left:50%;
  bottom:calc(-1 * var(--s-5) + 3px);width:7px;height:7px;margin-left:-4px;
  border-right:2px solid var(--n-300);border-bottom:2px solid var(--n-300);
  transform:rotate(45deg);z-index:1}
.gd-n{position:absolute;top:-7px;left:-7px;width:20px;height:20px;border-radius:50%;
  background:var(--navy);color:#fff;font-family:var(--display);font-size:var(--fs-label);
  font-weight:var(--fw-bold);display:flex;align-items:center;justify-content:center;
  line-height:1;z-index:2}
/* Spans rather than p and h4, because the whole step is inside an li that has
   to stay one grid cell. They are made block here: left inline, the instruction
   and its detail run together into one sentence, which is the opposite of the
   one-idea-per-line this component exists for. */
.gd-body{display:block;min-width:0;padding-top:2px}
.gd-t{display:block;font-size:var(--fs-body);font-weight:var(--fw-semi);color:var(--ink);
  line-height:var(--lh-snug);margin:0}
.gd-d{display:block;font-size:var(--fs-meta);color:var(--mut);line-height:var(--lh-snug);
  margin:var(--s-1) 0 0}
/* The exact strings to tick, set as what they are. A scope is copied character
   for character out of a search box, so it is monospace and it is selectable,
   and it sits under the step that says to search for it rather than in a
   paragraph three steps away. */
.gd-tick{list-style:none;margin:var(--s-2) 0 0;padding:0;display:flex;flex-wrap:wrap;gap:var(--s-2)}
.gd-tick li{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:var(--fs-meta);color:var(--n-700);background:var(--n-50);
  border:1px solid var(--n-200);border-radius:var(--r-sm);padding:2px var(--s-2);
  display:inline-flex;align-items:center;gap:var(--s-1);overflow-wrap:anywhere}
.gd-tick li::before{content:"";width:9px;height:5px;flex:none;
  border-left:2px solid var(--status-active-txt);border-bottom:2px solid var(--status-active-txt);
  transform:rotate(-45deg) translate(1px,-2px)}
/* THE THING NOT TO DO. It is not an error and it must not look like one, but it
   is the single most valuable line on the HubSpot guide, because the wrong key
   is the one the vendor puts in front of you first. Warm ground, no icon, no
   thick rule down the side. */
.gd-avoid{font-size:var(--fs-meta);color:var(--status-new-txt);background:var(--status-off-bg);
  border-radius:var(--r-sm);padding:var(--s-3) var(--s-4);margin:var(--s-4) 0 0;
  line-height:var(--lh-body);max-width:var(--mw-read)}
.gd-avoid b{color:var(--ink)}
.gd-jump{margin:var(--s-4) 0 0}
/* ---- the three phase guide ------------------------------------------------
   ONE SCREEN, BECAUSE THIS PAGE IS USED ON A SHARE. The eight step timeline
   above is for one person hunting one key on their own, where a tall column is
   fine. This is for a room being walked through a build, where the whole thing
   has to be visible at once or the person presenting scrolls while talking.

   THE MEASURE IS THE CARD, NOT A ch VALUE. The timeline caps its text at 56ch,
   which inside a card near 1000px leaves most of the width empty and every
   paragraph hugging the left edge. Three columns spend that width instead, so
   the text sets its own measure and there is no ragged gutter down the right. */
.gdp{list-style:none;margin:var(--s-3) 0 0;padding:0;display:grid;gap:var(--s-3);
  grid-template-columns:repeat(3,minmax(0,1fr));align-items:stretch}
.gdp-i{min-width:0;background:var(--n-50);border:1px solid var(--n-200);
  border-radius:var(--r-sm);padding:var(--s-4)}
/* IN THE HEADING RATHER THAN OVER THE CARD EDGE. Floated onto the border it
   collides with the card above it at every width the grid reflows at, and it
   read as a badge stuck on rather than as the first thing in the sentence. */
.gdp-n{width:20px;height:20px;border-radius:50%;background:var(--navy);color:#fff;
  font-family:var(--display);font-size:var(--fs-label);font-weight:var(--fw-bold);
  display:inline-flex;align-items:center;justify-content:center;line-height:1;
  margin-right:var(--s-2);flex:none}
.gdp-h{display:flex;align-items:center;font-size:var(--fs-body);font-weight:var(--fw-semi);
  color:var(--ink);line-height:var(--lh-snug);margin:0}
/* WHERE IT LIVES, SET AS A CLICK PATH RATHER THAN A SENTENCE. It is read while
   somebody clicks, so it is the path and nothing else. */
.gdp-w{display:block;font-size:var(--fs-label);color:var(--mut);
  line-height:var(--lh-snug);margin:var(--s-2) 0 0}
/* NO MARKERS, BECAUSE NOTHING ELSE IN THIS PRODUCT HAS THEM. Every list on the
   console sets list-style none and spaces its rows instead: .caplist, .glist,
   .fieldlist, .gd-steps and .gd-tick. A default disc was the single
   loudest reason this block did not look like the app it is in. */
.gdp-do{list-style:none;margin:var(--s-3) 0 0;padding:0;display:grid;gap:var(--s-2)}
.gdp-do li{font-size:var(--fs-meta);color:var(--mut);line-height:var(--lh-snug)}
.gdp .gd-tick{margin-top:var(--s-3)}
@media(max-width:900px){
  .gdp{grid-template-columns:minmax(0,1fr)}
}
@media(max-width:560px){
  .gd-step{grid-template-columns:36px minmax(0,1fr);gap:0 var(--s-3)}
  .gd-fig{width:36px;height:36px}
  .gd-step:not(:last-child) .gd-fig::after{top:36px;height:calc(100% + var(--s-5) - 36px)}
}
/* ---- templates and flows --------------------------------------------------
 *
 * THE READER IS THE REASON THIS LOOKS LIKE THIS. Three supers use this page to
 * agree what the platform says, and they do not read the same way: one wants
 * the shape of the thing in one glance, one reads every word, and one needs it
 * broken into steps that hold still. So every stage carries the same four parts
 * in the same order, always: a number, a plain sentence, what it costs to know
 * (channel, audience, timing) as separate chips, and the long version behind a
 * disclosure that starts closed. Nobody has to read the long version to follow
 * the flow, and nobody who wants it has to go and find it somewhere else.
 *
 * NOTHING IS CARRIED BY COLOUR ALONE. The status of a stage is a word first
 * ("Runs today", "Needs building"), and the colour is a second copy of that
 * word for people who read colour faster than text. That is the rule the pills
 * elsewhere in the product already follow and it matters more here, because
 * this page's whole job is to be understood by somebody who did not build it.
 *
 * THE SPINE IS A REAL <ol>. The vertical line and the numbered discs are drawn
 * with a border and a pseudo element on list items, so a screen reader gets
 * "list, 8 items, item 3 of 8" for free and the order is in the markup rather
 * than in the picture. An SVG diagram would have looked the same and said
 * nothing. */
.fl-intro{max-width:var(--mw-read);color:var(--n-700);margin:0 0 var(--s-4)}
/* THE TRACK IS THE CARDS, NOT A GUTTER BESIDE THEM, AND THAT IS THE SECOND
 * VERSION OF THIS. The first drew a spine in a 32px gutter with the numbers on
 * it, which looked like a process diagram and put every step card 32px to the
 * right of the page heading, the intro paragraph and every other card in the
 * product. That is precisely the defect this product's design brief singles out
 * as the one a human spots instantly and every automated check passes: the
 * cards were internally consistent and the same width, and the fault was only
 * in the relationship between blocks. The rule it states is that an indent has
 * to earn itself by carrying information the row would otherwise lose, and the
 * step number does not, because the order is already carried by the ordered
 * list, by reading order and by the numbers themselves wherever they sit.
 *
 * So the number moved onto the heading line and the line moved onto the card as
 * a left edge. Every block on the page now starts at one x, the sequence still
 * reads down the page as a column of discs, and it survives 375px, which the
 * gutter version did not. */
/* A phase, and the headings alone are the summary: somebody who reads only them
   has the shape of the product. They carry it alone now. Each one used to have a
   sentence under it repeating what the cards below already said, and the two
   that were saying something else say it in the heading instead.

   .lead survives for the claim page and the phone call, which are sections
   rather than phases and open on a fact the rows underneath do not carry. */
.fl-phase{margin:0 0 var(--s-6)}
.fl-phase>h2{font-family:var(--display);font-size:var(--fs-title);font-weight:var(--fw-bold);
  color:var(--navy);margin:0 0 var(--s-3)}
.fl-phase>.lead{margin:0 0 var(--s-3);color:var(--n-700);max-width:var(--mw-read)}
.fl-spine{list-style:none;margin:0;padding:0}
.fl-step{margin:0 0 var(--s-3);position:relative}
.fl-step:last-child{margin-bottom:0}
/* THE ARROW BETWEEN CARDS, AND IT IS A PSEUDO ELEMENT ON PURPOSE. Drawn as a
   list item it would be counted, so a three step phase would announce six
   items and every second one would be silent. As ::after it is invisible to a
   reader that does not need it and it is the strongest single cue for a reader
   who does: it says "then", which is the one word this page is about. */
.fl-step:not(:last-child){margin-bottom:var(--s-5)}
.fl-step:not(:last-child)::after{content:"";position:absolute;left:34px;bottom:-19px;
  width:9px;height:9px;border-right:2px solid var(--n-300);border-bottom:2px solid var(--n-300);
  transform:rotate(45deg)}
/* The fork. Two lanes side by side, because side by side is what "one or the
   other" looks like and a stacked pair looks like "first this, then that",
   which is the exact thing the old single list got wrong. */
.fl-fork{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-5);align-items:start}
/* A LANE IS A HEADING AND A COLOURED EDGE, NOT A BOX, AND IT STOPPED BEING A BOX
   ON 3 AUGUST 2026. It was a bordered panel with 12px of its own padding, so the
   three step cards inside it started 13px to the right of the five step cards
   outside it, on the one page whose stated rule is that every block starts at
   one x. Nothing else on this page nests a card inside a second container, and
   the box was the only reason this one did.

   What the box was carrying is carried by the two things that were always doing
   the work anyway: the heading, which names the branch in full, and the coloured
   top edge, which repeats the heading rather than replacing it. The gap went to
   var(--s-5) to keep the two columns reading as two, which is the job the side
   borders were doing badly. Read down a lane and the cards sit exactly where
   every other step card on the page sits. */
/* No radius at all, deliberately, and not `border-radius:0`: the top edge is a
   section rule and a rule bending round a corner is the thing the box used to
   do. There is nothing left to round. */
.fl-lane{border:0;border-top:3px solid var(--line);padding:var(--s-3) 0 0;background:none}
/* A 3px top edge and a word. The colour is the second copy of the label, never
   the only one: "A consultant takes it" and "Nobody takes it" say it in full
   before any colour is involved. */
.fl-lane.good{border-top-color:var(--status-active-txt)}
.fl-lane.warn{border-top-color:var(--status-new-txt)}
/* The label, and a status pill only where the two lanes differ in status. The
   sentence that used to sit under the label was a second copy of the label on
   the lead flow, and on the booking flow it was carrying a status that every
   card in the lane already carries as a pill. So it is the pill here too. */
.fl-lanehead{font-family:var(--display);font-size:var(--fs-body);font-weight:var(--fw-bold);
  color:var(--navy);margin:0 0 var(--s-3);display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-2)}
@media(max-width:820px){
  /* Stacked, and the lanes keep their headings and their coloured edges, which
     is what stops the pair reading as one continuous sequence once they are one
     above the other. */
  .fl-fork{grid-template-columns:1fr}
}
.fl-card{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  padding:var(--s-3) var(--s-4)}
/* The card as a control. display:block and text-align:left because a button
   defaults to neither, and font:inherit because a button defaults to the
   system UI font, which is how a card ends up in a different typeface from the
   page it sits on. */
button.fl-card{display:block;width:100%;text-align:left;font:inherit;cursor:pointer;
  position:relative;padding-right:var(--s-6)}
button.fl-card:hover{border-color:var(--line-strong);background:var(--n-25)}
button.fl-card:focus-visible{outline:2px solid var(--navy);outline-offset:2px}
button.fl-card .plain{display:block}
/* The affordance, and it is drawn rather than written. A chevron on the right
   edge is the one cue every phone and every website already teaches, so it
   needs no label and it does not add a word to a page whose whole problem was
   words. It grows on hover so the card feels like it is opening. */
.fl-open{position:absolute;right:var(--s-4);top:50%;width:8px;height:8px;
  border-right:2px solid var(--n-400);border-top:2px solid var(--n-400);
  transform:translateY(-50%) rotate(45deg);transition:right .12s ease}
button.fl-card:hover .fl-open{right:calc(var(--s-4) - 3px);border-color:var(--navy)}
/* The note marker. Not a button: the card is the button, and a control inside a
   control is the thing that makes people miss the one they meant. */
.fl-notemark{font-size:var(--fs-meta);color:var(--brand-solid);font-weight:var(--fw-semi)}
/* THE 3px RAIL DOWN THE LEFT OF EVERY STEP CARD IS GONE (3 August 2026), AND
   THE ARGUMENT FOR KEEPING IT IS RECORDED HERE BECAUSE IT WAS NEARLY KEPT.
   The rule this was re-decided against: a coloured bar down the side of a card
   is the most recognisable tell of generated interface, so it is a default to
   refuse rather than a ban. It can be earned. It has to be asked.

   The defence was that the rail is the sequence and the orange one marks "runs
   today". Both are true and neither survives the question "what would a reader
   lose". The sequence is carried three other ways already: the markup is a real
   <ol>, the number sits on the heading line, and a chevron is drawn between
   every pair of cards. The state is carried by the pill, which says "Runs today"
   in words, and by the icon tile, which takes the brand colour on the same
   cards. Decision 0016 says nothing is carried by colour alone, which makes a
   second copy of a word permitted; it does not make it necessary, and permitted
   plus unnecessary is the definition of decoration.

   What settled it: every stage on this page is live today, so the rail was the
   same orange on all eight cards and distinguished nothing at all. The first
   card that says "Needs building" would have been the first time it meant
   anything, and by then the pill and the icon would have said it first.

   The padding stays at the full var(--s-4). This was 3px of border against
   calc(var(--s-4) - 3px) of padding an hour ago, so that the text landed at 16
   rather than 19; taking the border out and putting the padding back means the
   text has not moved, only the paint. */
/* The head: picture, number, title, state. Always those four, always that
   order, on every card on the page. */
/* flex-wrap, or on a phone the state pill holds its width and squeezes the
   title into three lines rather than dropping below it. */
.fl-head{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-2);margin:0 0 var(--s-2)}
.fl-card h3{font-family:var(--display);font-size:var(--fs-title);font-weight:var(--fw-semi);max-width:var(--mw-read);
  color:var(--navy);margin:0;line-height:var(--lh-tight);min-width:0;
  display:flex;align-items:baseline;gap:var(--s-2)}
/* The picture. A tile rather than a bare glyph, so it holds the same shape and
   the same weight on every card whatever is inside it, which is what makes the
   column of them scannable at all. flex:none, or a long title squashes it. */
.fl-icon{flex:none;width:34px;height:34px;display:inline-flex;align-items:center;
  justify-content:center;border-radius:var(--r-sm);background:var(--n-50);
  border:1px solid var(--n-200);color:var(--n-600)}
.fl-step.now .fl-icon{background:var(--card);border-color:var(--brand-solid);color:var(--brand-solid)}
.fl-num{flex:none;font-size:var(--fs-meta);font-weight:var(--fw-bold);color:var(--mut);
  font-variant-numeric:tabular-nums}
.fl-head>.fl-state{margin-left:auto;flex:none}
/* The two facts, label above value so the pair stays together when it wraps.
   Spans rather than a <dl>, because the card is a <button> now and a definition
   list is not allowed inside one: the same two labels appear on every card, so
   nothing is lost by saying it in plain text. */
.fl-mini{display:flex;flex-wrap:wrap;gap:var(--s-2) var(--s-5);margin:var(--s-3) 0 0;align-items:baseline}
.fl-mini>span{min-width:0;display:block}
.fl-mini .k{display:block;font-size:var(--fs-meta);color:var(--mut)}
.fl-mini .v{display:block;margin-top:1px;color:var(--ink);font-weight:var(--fw-med)}
/* The messages a step sends, inside its dialog. A list, because "what this
   sends" is usually more than one thing and six of them in a sentence is a
   sentence nobody finishes. */
.fl-sendbox{margin:var(--s-4) 0 0;border-top:1px solid var(--line);padding-top:var(--s-3)}
.fl-sendbox>.k{display:block;font-size:var(--fs-meta);color:var(--mut);margin:0 0 var(--s-2)}
.fl-sendbox ul{list-style:none;margin:0;padding:0;display:grid;gap:var(--s-1)}
/* A door one level further down, and it looks like one. Full width and a
   chevron, the same shape as the card that got you here, so the way deeper is
   always the same gesture. */
.fl-godeeper{display:flex;width:100%;align-items:center;justify-content:space-between;
  gap:var(--s-2);font:inherit;font-weight:var(--fw-semi);color:var(--navy);text-align:left;
  background:var(--card);border:1px solid var(--line-strong);border-radius:var(--r-sm);
  padding:var(--s-2) var(--s-3);cursor:pointer}
.fl-godeeper::after{content:"";flex:none;width:7px;height:7px;
  border-right:2px solid currentColor;border-top:2px solid currentColor;transform:rotate(45deg)}
.fl-godeeper:hover{background:var(--n-50);border-color:var(--navy)}
.fl-godeeper:focus-visible{outline:2px solid var(--navy);outline-offset:1px}
/* The one sentence, repeated at the top of the dialog the card opened. Not
   redundant: the card is gone behind the dialog, and starting the detail with
   the line they pressed on is what tells somebody they opened the right thing. */
.fl-plainlead{font-size:var(--fs-input);color:var(--ink);margin:0 0 var(--s-3)}
/* THE ONE SENTENCE, AND IT IS DELIBERATELY THE BIGGEST TEXT IN THE CARD AFTER
   THE HEADING. It is the only part somebody has to read to follow the flow. */
.fl-card .plain{margin:0;color:var(--ink);max-width:var(--mw-read)}
.fl-chips{display:flex;flex-wrap:wrap;gap:var(--s-2);margin:var(--s-3) 0 0;align-items:center}
.fl-chip{display:inline-flex;align-items:center;gap:var(--s-1);font-size:var(--fs-meta);
  color:var(--n-700);background:var(--n-50);border:1px solid var(--n-200);
  border-radius:var(--r-pill);padding:2px var(--s-2);white-space:nowrap}
.fl-chip .k{color:var(--mut)}
.fl-state{font-size:var(--fs-meta);font-weight:var(--fw-semi);border-radius:var(--r-pill);
  padding:2px var(--s-2);white-space:nowrap}
.fl-state.live{background:var(--status-active-bg);color:var(--status-active-txt)}
.fl-state.build{background:var(--status-new-bg);color:var(--status-new-txt)}
.fl-state.blocked{background:var(--status-alert-bg);color:var(--status-alert-txt)}
/* The disclosure. `details` rather than a built toggle for the reason the Setup
   card gives: it needs no component, it is keyboard operable and announced
   without a line of script, and the browser remembers nothing between views,
   which is right here because a stage that reopened itself would move the page
   under somebody who had scrolled past it. */
/* The disclosure and the Discuss control share one row. They had a line each,
   which spent 64px of every card on two controls and gave each card two
   horizontal rules to read past. align-items:flex-start, or the button drifts
   to the middle of an expanded disclosure. */
.fl-foot{display:flex;gap:var(--s-3);align-items:flex-start;justify-content:space-between;
  margin:var(--s-3) 0 0;border-top:1px solid var(--line);padding-top:var(--s-2)}
.fl-foot>.fl-more{flex:1;min-width:0}
.fl-foot>.fl-acts{margin:0;flex:none}
.fl-more{margin:0}
.fl-more>summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;
  gap:var(--s-1);font-size:var(--fs-meta);font-weight:var(--fw-semi);color:var(--navy);
  min-height:32px}
.fl-more>summary::-webkit-details-marker{display:none}
.fl-more>summary::after{content:"";width:7px;height:7px;border-right:2px solid currentColor;
  border-bottom:2px solid currentColor;transform:rotate(45deg) translate(-2px,-2px)}
.fl-more[open]>summary::after{transform:rotate(-135deg) translate(-2px,-2px)}
.fl-more>summary:focus-visible{outline:2px solid var(--navy);outline-offset:2px}
.fl-more .fl-body{padding:var(--s-2) 0 0;color:var(--n-700);max-width:var(--mw-read)}
.fl-more .fl-body p{margin:0 0 var(--s-2)}
.fl-more .fl-body p:last-child{margin-bottom:0}
/* A LIST STARTS WHERE THE PARAGRAPH ABOVE IT STARTS. It had padding-left:16px,
   which is the browser's own indent restated as a token, so a list inside a
   disclosure stepped 16px right of the sentences either side of it in the same
   box. An indent has to earn itself by carrying information the row would
   otherwise lose, and "these three are a list" is already carried by the
   bullets. So the bullet takes the paragraph's x and the text clears it, which
   also means a wrapped line returns to the text rather than under the bullet,
   which list-style-position:inside would not have given. */
.fl-more .fl-body ul{margin:0 0 var(--s-2);padding-left:0;list-style:none}
.fl-more .fl-body li{margin:0 0 var(--s-1);padding-left:var(--s-3);position:relative}
.fl-more .fl-body li::before{content:"";position:absolute;left:1px;top:.6em;
  width:4px;height:4px;border-radius:50%;background:var(--n-400)}
/* A branch off the spine: the customer text is not step 9, it hangs off a step.
   Drawn beside the track rather than inside it, because putting it in the
   numbered list would say it happens to every lead, and it does not. The
   appointment ladder was the second branch here and went with the module. */
.fl-branch{margin:var(--s-5) 0 0}
/* No .sub rule under this heading any more: every section that had one was
   restating the heading or the pills on the cards below it, and the two that
   carried a real fact carry it in the heading now. The heading's own bottom
   margin does the spacing the sub used to. */
.fl-branch>h2{font-family:var(--display);font-size:var(--fs-title);font-weight:var(--fw-semi);
  color:var(--navy);margin:0 0 var(--s-3)}
.fl-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:var(--s-3)}
/* THE SET TABS ARE A TABLE, AND THE FIRST VERSION WAS NOT, WHICH IS WHY IT WAS
 * UNREADABLE. Every notification was a stacked block carrying a name, a key, a
 * trigger sentence, three chips, a disclosure and two buttons: eight lines each,
 * fifteen of them, three thousand pixels of near-identical shapes with no
 * columns to compare down. Nothing scanned, because nothing lined up.
 *
 * These are sets you look things up in, and this product already has the
 * component for that. Four columns, one row per template, the row opens
 * everything. The `Reaches` column exists because "does this one go to a member
 * of the public" is the single most important fact on the page and it was
 * previously buried in a sentence inside a chip.
 *
 * ONE TARGET PER ROW. The old row had a disclosure, a See what it says button
 * and a Discuss button, which is three ways to open three subsets of the same
 * thing. Now the row opens one dialog that holds all of it, and the only other
 * thing in the row is the note count, which is information rather than a
 * control. */
/* The row list survives for the two places that are genuinely a short list of
   prose rather than a set of records: the open decisions, and the phone call
   script, which is read straight down in order like the flow and would be
   actively worse hidden one line at a time behind fifteen clicks. */
.fl-rows{border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;background:var(--card)}
.fl-row{border-bottom:1px solid var(--line);padding:var(--s-3) var(--s-4)}
.fl-row:last-child{border-bottom:0}
.fl-row .rname{font-family:var(--display);font-weight:var(--fw-semi);color:var(--navy);
  font-size:var(--fs-body);display:block;max-width:var(--mw-read)}
.fl-row .rwhen{display:block;font-size:var(--fs-meta);color:var(--mut);margin:2px 0 0;max-width:var(--mw-read)}
.fl-row .rtrig{display:block;margin:var(--s-2) 0 0;color:var(--n-700);max-width:var(--mw-read)}
/* An open question is a door too, the same as a step card. Same gesture, same
   chevron, so there is one thing to learn on this page and not three.

   THE THREE ZEROED BORDERS ARE A BUG FIX, NOT TIDINESS (3 August 2026). Every
   bare <button> in this product is navy with a 1px navy border, from tokens.css.
   This one cleared the background and not the border, so each open question was
   drawn inside a navy hairline box and its text started 1px right of every other
   row in the same list. The bottom border is left alone deliberately: .fl-row
   sets it to the divider colour and .fl-row:last-child removes it, and a
   shorthand here would beat both and put a rule under the last question. */
button.fl-qrow{display:block;width:100%;text-align:left;font:inherit;background:none;
  border-left:0;border-right:0;border-top:0;
  cursor:pointer;position:relative;padding-right:var(--s-6)}
button.fl-qrow:hover{background:var(--n-25)}
button.fl-qrow:focus-visible{outline:2px solid var(--navy);outline-offset:-2px}
button.fl-qrow .fl-notemark{display:inline-block;margin-top:var(--s-2)}
/* The framing, and it is the first thing on the page for a reason: somebody who
   has never seen this product needs to know what it is trying to be before they
   are shown what it does today.

   ITS ORANGE RAIL WENT WITH THE STEP CARDS' (3 August 2026), and this one had
   less of a defence than they did. Theirs at least claimed to carry the sequence
   and the live state. This one carried nothing: the block already has a tinted
   ground that separates it from the white page, and it already opens with
   "Where this is going" and "Where we are" in bold, which is the framing said in
   words. An accent bar on top of that is the brand asserting itself on the one
   block whose job is to be read.

   The corner radius came back to all four with it. It was 0 on the left only
   because a bar was sitting there, which is the tell within the tell: a shape
   bent around a decoration. Padding is the full var(--s-4) all round now, so the
   text sits where the corrected calc() put it and nothing has moved.

   The hairline replacing the bar is not decoration by another name, it is what
   makes the sums come out: every other block on this page is a bordered box, so
   a tinted panel with no border put its text 1px to the left of all of them.
   Same pairing .fl-sample already uses, a tint and a hairline, and the text now
   lands on the same x as a step card's. */
.fl-goal{background:var(--n-25);border:1px solid var(--line);border-radius:var(--r-md);
  margin:0 0 var(--s-4);padding:var(--s-3) var(--s-4)}
.fl-goal p{margin:0 0 var(--s-2);max-width:var(--mw-read);color:var(--n-700)}
.fl-goal p:last-child{margin-bottom:0}
.fl-goal b{color:var(--navy)}
.fl-tname{font-weight:var(--fw-semi);color:var(--navy)}
.fl-tkey{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:var(--fs-meta);color:var(--mut);font-weight:400;margin-top:1px}
/* Clamped to one line so every row is the same height and the columns stay
   readable as columns. The full text is in the dialog the row opens. */
.fl-clamp{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fl-ch{color:var(--n-700)}
.fl-cust{color:var(--status-alert-txt);font-weight:var(--fw-semi)}
/* The note count. Quiet at zero, because forty grey zeros down a column is
   noise; it only earns colour once somebody has actually said something. */
.fl-n{color:var(--faint)}
.fl-n.some{color:var(--brand-solid);font-weight:var(--fw-semi)}
.fl-acts{display:flex;flex-wrap:wrap;gap:var(--s-2);align-items:center;margin:var(--s-3) 0 0}
/* Discussion. The count is on the button and not beside it, so there is one
   thing to aim at and it is the same thing whether or not anybody has written
   anything yet. */
.fl-disc .count{font-variant-numeric:tabular-nums;margin-left:var(--s-1);color:var(--mut)}
.fl-disc[data-n]:not([data-n="0"]) .count{color:var(--brand-solid);font-weight:var(--fw-semi)}
/* The note list itself reuses .rmcm and .rmc from the roadmap. There is one
   comment component in this product and this is not a second one. */
/* A template name inside a sentence. It navigates, so it is a button and not an
   anchor, and it is styled as text rather than as a control because it sits
   mid-sentence and a fourth button treatment on this page would break the rule
   the whole redesign was about. Underline on hover only, so the sentence reads
   as a sentence until somebody goes looking. */
.linkish{background:none;border:0;padding:0;font:inherit;color:var(--navy);
  font-weight:var(--fw-semi);cursor:pointer;text-decoration:underline;
  text-underline-offset:2px}
.linkish:hover{color:var(--brand-solid)}
.linkish:focus-visible{outline:2px solid var(--navy);outline-offset:2px;border-radius:2px}
.fl-sample{background:var(--n-50);border:1px solid var(--n-200);border-radius:var(--r-sm);
  padding:var(--s-3);margin:0 0 var(--s-3)}
.fl-sample .lbl2{display:block;font-size:var(--fs-meta);color:var(--mut);margin:0 0 var(--s-1)}
.fl-sample .txt{margin:0;white-space:pre-wrap;word-break:break-word}
/* The Copy as text control shares the What it says heading's line. It is the
   heading's own action and it belongs on it: a control on its own row would be a
   third band of furniture in a dialog that is already facts, wording and
   discussion. flex-wrap, so a narrow dialog drops it under the heading rather
   than squeezing the heading. */
.fl-copyhead{display:flex;flex-wrap:wrap;gap:var(--s-2);align-items:center;
  justify-content:space-between;margin:0 0 var(--s-1)}
.fl-copyhead>.rmcmh{margin:0}
/* The string the clipboard reads, parked in the DOM because intWireCopy copies
   what is in an element rather than what is in a variable. Not the hidden
   attribute: a stylesheet that gives <pre> a display would beat it, and the one
   thing this element has to do is still be there when the helper looks. */
.fl-copysrc{display:none}
/* The rendered email preview. Sandboxed, because it is HTML this product built
   but a preview pane that can run script is a preview pane that can read the
   session it is rendered inside. */
.fl-frame{width:100%;height:460px;border:1px solid var(--line);border-radius:var(--r-sm);background:#fff}
/* THE CLAIM PAGE IS FRAMED AT THE WIDTH IT IS BUILT FOR, NOT AT THE DIALOG'S.
   claim.html wraps at 460px and centres, so a full width frame draws a narrow
   column stranded in white and invites somebody to report the layout as broken.
   500px is that column plus its gutters, which is what a consultant on a phone
   sees and close to what one on a laptop sees. Taller than the email frame
   because this is a whole page: the claimable state carries the summary, the
   enquiry fields and the fixed claim bar, and the bar pins to the bottom of the
   frame exactly as it pins to the bottom of a phone. */
.fl-claimframe{max-width:500px;height:620px;margin:0 auto;display:block}
@media (max-width:640px){
  /* ALL THREE BLOCK SHAPES DROP A STEP TOGETHER, AND ONLY THE CARD USED TO.
     A phone is 375px, so 16px of padding on each side spends nine per cent of
     the width on nothing, which is why the card gave a step back. The goal panel
     and the row lists did not, so on the width where the difference is most
     visible the same page put its text at two x values 4px apart. One step, one
     breakpoint, every block. */
  .fl-card,.fl-goal,.fl-row{padding:var(--s-3)}
  .fl-frame{height:340px}
}

/* ---- the Call control, DC-101 ---------------------------------------------
 *
 * Call is an <a href="tel:"> on the board now, not a <button>, because DC-99
 * settled that the navigation has to BE the anchor: the user agent handles a
 * real tel: anchor, and a click handler that sets location.href is not reliably
 * handled everywhere this product is opened.
 *
 * An anchor gets none of a button's user agent styling, so these rules are what
 * make it look like the control it replaced. shell.css already sizes button.sm
 * and tokens.css already colours .btn-primary; both selectors name the element,
 * so neither reaches an anchor on its own.
 *
 * WHY THIS FILE AND NOT shell.css. shell.css is shared with claim.html and
 * signup.html, and claim.html carries its own a.bigbtn rule for the same reason.
 * Widening the shared sheet to cover both shapes would change two other pages to
 * fix one.
 */
a.sm, a.btn-primary{
  display:inline-flex;align-items:center;justify-content:center;
  text-decoration:none;box-sizing:border-box;
}
a.sm{padding:var(--s-1) var(--s-3);font-size:var(--fs-meta);
  background:var(--navy);border:1px solid var(--navy);color:#fff;
  border-radius:var(--r-sm);font-family:var(--display);font-weight:600;cursor:pointer}
a.sm:hover{background:var(--navy)}
/* THE DEMOTION IN shell.css IS AN ELEMENT SELECTOR AND THIS ANCHOR CANNOT MATCH
   IT, WHICH IS THE SAME TRAP AS THE PARAGRAPH ABOVE, ONE LEVEL UP.
   shell.css demotes a repeated control in a table cell to a quiet outline, and
   the whole argument for it is that filled is a rank and a rank means nothing
   when eighteen rows hold it. It selects `td>button:not(...)`. Claim is a
   <button> so it is demoted. Call is an <a class="sm"> so it is not, and it kept
   the filled navy above. The result was one board column drawing the same
   decision two different ways, which nobody chose and which is exactly what
   Chirag read as not being able to tell what is clickable.

   Fixed here rather than in shell.css because a.sm is declared here, for the
   reason given above: claim.html and signup.html carry their own anchor-button
   shapes and widening the shared sheet would change two pages to fix one.
   shell.css keeps the rule for buttons; this is its anchor half.

   The hover fill is the other half of the demotion and is copied deliberately,
   not inherited: quiet at rest, unmistakably the action under the pointer. */
td>a.sm{background:var(--n-0);color:var(--navy);border-color:var(--line-strong)}
td>a.sm:hover{background:var(--navy);color:#fff;border-color:var(--navy)}
/* WHICH PART OF A ROW OPENS THE LEAD. The row has carried data-open, tabindex
   and cursor:pointer since it was built, and that was the entire signal. A
   pointer is only discoverable once you are already on the row, it does not say
   what it opens, and on a table of plain text it competes with the control in
   the last column. The subject of the row now underlines with the row, so the
   name reads as the way in and the button reads as the action, which is what
   they already were.

   NOT AN ANCHOR, DELIBERATELY. The handler is on the row, and this cell already
   holds real anchors for tel: and mailto:. A third would put two competing
   targets in one cell and nest a link inside a clickable row, for a cue that
   costs one rule. */
tr.rowlink:hover .cname,
tr.rowlink:focus-visible .cname{text-decoration:underline}
/* THE HALF OF THAT RULE THAT WAS NEVER FINISHED, AND IT IS WHY THE LEAD PAGE
   HEAD LOOKED WRONG. a.sm above sets its own padding and font-size because the
   ones it needs live on `button` in shell.css, an ELEMENT selector an anchor can
   never match. a.btn-primary shares the display and box-sizing line and then
   sets neither, so tokens.css gave the Call control its colour, weight, border
   and radius while its size came from nowhere: no padding at all, and the
   inherited font size rather than --fs-body.

   Beside two ghost BUTTONS carrying padding:8px 16px, that renders as a short
   orange chip wedged between two taller outlined ones, which is exactly what
   Chirag photographed. Same values as `button`, so the three controls in that
   row are finally the same height. */
a.btn-primary{padding:var(--s-2) var(--s-4);font-size:var(--fs-body)}

/* The number beside the Call control, with its own copy button. The number is
 * already a tel: link in the row and in the drawer and has been since before
 * this card; what was missing is a way to get it onto the clipboard for a
 * desktop with no handler registered, which is the one machine where tapping
 * Call does nothing at all. user-select is explicit because the surrounding
 * table sets none. */
/* ---- the two setup cells, All accounts and the account picker ---------------
 *
 * WHY A CIRCLE AND NOT A PILL. Every other state on this product is a pill with
 * a word in it, and eight of them down a column is eight words to read where the
 * question is a yes or a no. The circle is scanned rather than read, which is
 * the only reason this column earns its width on a table whose job is to be
 * looked down once.
 *
 * A GREY CIRCLE IS "no". A BARE HYPHEN IS "not read". The two are deliberately
 * different shapes and not two shades of the same one, because this file has
 * used a plain faint hyphen to mean "could not be read just now" since the
 * board's first duration cell, and a failed call that looks like a dead client
 * takes that client off the ring list.
 *
 * .nofix, NOT .ok, AND THAT IS NOT A PREFERENCE. .ok already exists twice as a
 * compound modifier, on .pill.ok at ten call sites and on .rmwait.ok. A bare
 * .ok rule here would reach every one of them and set them semi-bold green,
 * with nothing failing and nobody looking. The mock draws this cell as .ok
 * because the mock is a standalone page with no pills on it.
 *
 * Both tick and dash borrow the status tokens rather than naming colours, so
 * they move with the palette like every other state in the product. */
.tick,.dash{display:inline-flex;align-items:center;justify-content:center;
  width:20px;height:20px;border-radius:50%;font-size:11px;font-weight:700}
.tick{background:var(--status-active-bg);color:var(--status-active-txt);
  border:1px solid var(--status-active-line)}
.dash{background:var(--status-off-bg);color:var(--n-400);
  border:1px solid var(--status-off-line)}
/* The ring script. It wraps, because four reasons on one client is a real row
 * and nowrap would push the table sideways on the screen it is least wanted on. */
.tofix{color:var(--status-alert-txt);font-weight:var(--fw-med)}
.nofix{color:var(--status-active-txt);font-weight:var(--fw-semi)}
/* THE CLIENTS TABLE COLUMNS, AND THE SETUP CELL IS THE ONLY FLEXIBLE ONE.
   Under auto layout the longest setup string in any one row set where Live,
   Leads and Waiting began, so the table moved as a client got set up and the
   counts had no fixed edge to be read down. The min-width is the four fixed
   columns plus a 340px floor for the sentence, below which .tblwrap scrolls. */
.clienttbl{table-layout:fixed;min-width:936px}
.clienttbl col.c-client{width:340px}
.clienttbl col.c-live{width:64px}
.clienttbl col.c-num{width:96px}
.clienttbl col.c-setup{width:auto}

/* .dialrow WENT WITH THE CONTROL IT STYLED. It laid out the customer's number
   and a Copy button inside the lead page action row, which is gone: the number
   is still on the same screen as a tel: link in the Details panel, so nothing
   was lost by removing it. .num itself lives in shell.css and is untouched. */

/* THE ROSTER PASTE BOX IS MONOSPACE BECAUSE THE COLUMNS ARE READ DOWN. A name
   and an email in a proportional face do not line up, so a line missing its
   mobile looks like every other line. It scrolls rather than wrapping, for the
   same reason .raw does: one long pasted row must not widen the page. */
.rspaste{display:block;width:100%;box-sizing:border-box;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:var(--fs-meta);line-height:var(--lh-body);color:var(--n-700);
  background:var(--card);border:1px solid var(--line-strong);border-radius:var(--r-sm);
  padding:var(--s-2) var(--s-3);white-space:pre;overflow:auto}
.rspaste:focus{outline:none;border-color:var(--navy);box-shadow:var(--focus-ring)}
/* Check, then Apply, then the line saying which of them is live. Apply carries
   the filled treatment and sits disabled until a check comes back ok, so the
   order of the two actions is legible before either is pressed. */
.rsacts{display:flex;flex-wrap:wrap;gap:var(--s-3);align-items:center;margin:0 0 var(--s-4)}
/* .sub is scoped to .pagehead in shell.css, so a secondary line anywhere else
   in the product inherits body text and reads as loud as the sentence above it.
   This is that treatment, named for this screen rather than widened. */
.rssub{font-size:var(--fs-meta);color:var(--mut)}
/* What she pasted, printed the way she pasted it. A tab collapsed to a space
   turns a five column line into a four column one on screen, which is the
   reader checking the wrong text against the problem beside it. */
.rsraw{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:var(--fs-meta);white-space:pre}
