/* One stylesheet, every logged-in page. The tokens are Fede's, lifted from
   the landing page he shipped on 17 Aug (`landing.html`, its own `:root`) so
   the workspace and the front door are one product.

   They had drifted badly: the landing is warm paper, a transitional serif over
   Instrument Sans, navy, square corners; the workspace was cool blue-grey,
   system sans, #1c4ed8, 10px radius. Signing in changed companies. The header
   of this file has claimed since day one that it existed to stop exactly that,
   which is worth remembering the next time a page defines its own palette
   inline — that is what actually broke it, not a missing intention.

   `landing.html` still carries its own copy, because it is a compiled export
   from Claude Design and re-exporting it is Fede's loop, not ours. **When a
   token changes there, change it here.** `tests/test_workspace.py` compares
   the two lists and fails when they diverge, so this is checked rather than
   remembered. */

/* The palette is declared for the workspace *and for a slide*, and the dark
   override below is declared for the workspace only. That one extra selector
   is the whole fix for a bug that made the product unusable after dark: a
   slide's ground is white because the .pptx's ground is white — the deck theme
   sets it and must — while every word on it was painted with `--text`, which
   inverts. In dark mode 38 text nodes on the slide under review were
   near-white on white. Unreadable, on every slide of every deck, silently,
   because nobody reviews in dark.

   A slide is a picture of a file. The file has no dark mode, so neither can
   the picture: everything inside `.slide` keeps the light values, including
   the aliases, which resolve where they are declared and so have to be
   re-declared here rather than inferred from `--navy`. */
:root, .slide {
  /* --- Fede's palette, verbatim ------------------------------------- */
  --ink:      #0B0704;   /* the dark ground: topbar, primary button, cover */
  --paper:    #FFFFFF;
  --bone:     #EFEFEF;   /* type on the dark ground */
  --text:     #0B0704;
  --text-2:   #545454;
  --text-3:   #6C6C6C;
  --muted:    #787878;   /* eyebrows, captions */
  --navy:     #3A2A1C;
  --sky:      #B0A08C;   /* the one hover colour */
  --rule:     #E4E4E4;
  --rule-2:   #D5D5D5;
  --card:     #FAFAFA;

  --sans:  "Instrument Sans", Helvetica, Arial, sans-serif;

  /* --- what the workspace calls them --------------------------------
     Aliases rather than a rename, so six hundred lines of rules written
     against the old names keep working and the diff stays readable. New
     rules should prefer the names above. */
  --ink-soft:    var(--text-2);
  --ink-faint:   var(--muted);
  --line:        var(--rule);
  --shell:       var(--card);
  --accent:      var(--navy);
  --accent-soft: #EFECE8;
  --warn:        #8A4A2C;
  --warn-soft:   #F7EFEA;
  --good:        #2C6E49;

  /* Square, like the landing's buttons. 1px reads as "drawn", 0 as "unset". */
  --radius: 2px;
  --measure: 62ch;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --ease: 160ms ease;

  /* --- the shell, added 19 Aug --------------------------------------
     Fede: "non toccare funzionalità, riguarda tutta la UI e la UX." The
     palette was never the problem — these are the two things it did not
     have. **Elevation**, so a pane, a menu and the slide read as three
     planes rather than three fills of the same paper. And a **spacing
     scale**, because every gap in this file was picked by hand and no two
     panes were inset by the same amount.

     Warm shadows, not black: a neutral shadow on paper this warm reads as
     grey smudge. */
  --lift-1: 0 1px 2px rgba(15, 9, 8, .05);
  --lift-2: 0 18px 40px -20px rgba(15, 9, 8, .28), 0 2px 6px rgba(15, 9, 8, .05);
  --bar: 56px;          /* the topbar, and the offset everything sticky uses */
  --pad: 1.15rem;       /* the inset of a pane, everywhere */

  /* The stage is width-driven — `fitSlide` scales a 1280x720 slide by the
     width of its box — so a full-width pane draws a slide taller than the
     window and the deck you are reviewing scrolls. This is the height the
     stage does *not* get: the bar, the steps, the note row under the slide
     and the pane's own inset. Cap the width at 16/9 of what is left and a
     slide always fits, at any window size, with no measurement. */
  --stage-reserve: 13.5rem;
  --stage-w: calc((100dvh - var(--stage-reserve)) * 16 / 9);

  /* The ink that marks a thing as chosen — the live tab, the open deal, the
     slide on the stage, the primary button. It is `--ink` on paper, and it
     has to inverch in dark mode or every one of those marks disappears into
     the ground: the underline under the live step, the edge on the open
     deal and the border on the current thumbnail were all invisible in dark,
     because `--ink` is the one colour in Fede's palette that does not move.
     `--ink` itself must not move — the deck's cover and its theme fall back
     to it, and those have to match the .pptx in any browser. */
  --mark: #0B0704;
  --on-mark: #FFFFFF;
}

/* The landing page is light only — it is a video hero on a dark ground and
   has no dark variant. Rather than invent one for half the product, the
   workspace keeps a dark mode but derives it from the same hues. */
/* Dark, built from our own two tokens. Rewritten twice on 22 Aug.

   The first attempt took hebbia.com's ground (#0E0B0B) and moved the accent
   into their indigo. Tommaso, correctly: *"let's not blatantly copy. we should
   build our own language tailored for consultants. clean, professional,
   confident."* Two things in that pass were genuinely theirs — an exact hex
   and an accent hue — and neither had a reason beyond where it came from.

   The answer was already in the palette. Fede defined a dark surface on day
   one and only the deck ever used it:

       --ink:  #140F13   the dark ground: topbar, primary button, cover
       --bone: #EFEFF1   type on the dark ground

   (Those two hexes are Tommaso's, 24 Aug, replacing Fede's #0A0F14/#F2F0EA.
   The *structure* below is unchanged and is the point: dark is derived from
   whatever those two are, so re-colouring the product is two values and not a
   second palette to keep in step.)

   So the workspace after dark wears what the *deck's cover* wears. That is the
   register the work is in — a CDD is navy and bone, on paper and on a screen —
   and it is ours in the only way that counts: nothing here is chosen, it is
   derived. The ground is `--ink` exactly; the type is `--bone` exactly; the
   accent is `--navy` lightened until it holds on it; the rules are the ground
   a few steps up.

   Note the pairing this produces is *warm type on a cool ground*, which is not
   what the first pass built and not what Hebbia does. It is what Fede's two
   tokens say when you put them together, and it is why the deck's cover looks
   the way it does.

   The visit was still worth it. It is what showed that our dark half was
   incoherent at all — the third fault this month that existed only because
   nobody reviews in dark, after the missing selected state and the white-on-
   white slides. Light is untouched, the landing page is untouched, and the
   palette-parity test reads the block that defines `--ink`, which is the light
   one. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper:    #0B0704;   /* `--ink`, exactly: the ground the deck's cover uses */
    --card:     #15100A;
    --bone:     #EFEFEF;
    --text:     #EFEFEF;   /* `--bone`, exactly */
    --text-2:   #9E9C99;
    --text-3:   #78766F;
    --muted:    #787878;   /* the caption grey, unchanged from light */
    --rule:     #1D170F;
    --rule-2:   #2A2317;
    --navy:     #A89076;   /* `--navy` lightened until it holds on the ground */
    --sky:      #C0AC94;
    --accent-soft: #1A140C;
    --warn:      #D49A72;
    --warn-soft: #2A1E12;
    --good:      #74C69D;
    /* On a dark ground a drop shadow is invisible; the plane has to be told
       apart by a lighter edge instead. */
    --lift-1: 0 1px 0 rgba(240, 239, 238, .05);
    --lift-2: 0 18px 40px -20px rgba(0, 0, 0, .8), 0 0 0 1px rgba(240, 239, 238, .07);
    --mark:    #EFEFEF;    /* bone on ink, the way the cover marks its title */
    --on-mark: #0B0704;
  }
}* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.6 var(--sans);
  color: var(--text);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

/* The workspace is an application, not a document: the window is the frame and
   the panes scroll inside it. `body.app` says which pages are that — the
   landing, the templates editor and the source register are documents and go
   on scrolling. Without the class here, `.cols`' fixed height and the page's
   own scrollbar fought each other and the steps scrolled away from the deck
   they were stepping through. */
body.app {
  height: 100dvh; overflow: hidden;
  display: flex; flex-direction: column;
}

a { color: var(--navy); text-decoration: none; }
a:hover { color: var(--text); }
::selection { background: var(--navy); color: #fff; }
:focus-visible { outline: 2px solid var(--sky); outline-offset: 2px; }

/* Display type follows the landing, and on 21 Aug the landing stopped setting
   it at 300. Newsreader at 300 is thin and wide, and both of those are why the
   page read as generated: it is one of the few display serifs every machine-
   made page reaches for, set at the weight that flatters nothing. Source Serif
   4 at 600 is what Harvey and Rogo actually run, and the deck's own theme has
   wanted a serif headline from the start, because "a serif headline is most of
   the boutique look". `fonts.css` carries the reasoning. */
h1, h2, h3 { font-family: var(--sans); font-weight: 600; line-height: 1.15;
             letter-spacing: -.021em; margin: 0 0 .6rem; }
p { margin: 0 0 1rem; }
code, .mono { font-family: var(--mono); font-size: .875em; }

.wrap { max-width: 68rem; margin: 0 auto; padding: 0 1.5rem; }
.measure { max-width: var(--measure); }
.muted { color: var(--ink-soft); }
/* `--text-3`, not `--muted`. These were two different warmths until 24 Aug —
   `--muted` was #8A8578, a khaki that read as washed-out gold on a sentence —
   and both are neutral greys now, so the distinction is smaller than it was.
   It is kept because the sizes are different: `--muted` is for an 11px tracked
   eyebrow, this class is on twenty-three running sentences. */
.faint { color: var(--text-3); font-size: .85rem; }

/* --- buttons --------------------------------------------------------- */

/* `hidden` is a UA rule (`[hidden] { display: none }`) and it loses to any
   class that sets `display`. `.btn` sets `inline-flex`, so every button this
   app hides was hidden in the DOM and visible on the screen — "Address notes
   & rebuild" sat under the notes panel of every deal that had no notes to
   address, offering an action that would have been refused. */
[hidden] { display: none !important; }

/* Height-driven, square, 160ms — the landing's shape. Its buttons all sit on
   a dark ground and come in bone and ghost; the workspace sits on paper, so
   the primary inverts to the ink ground and ghost keeps its rule. Hover is
   --sky either way, which is the one hover colour in the product. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  height: 38px; padding: 0 18px; border-radius: var(--radius);
  border: 1px solid var(--mark); background: var(--mark); color: var(--on-mark);
  font: inherit; font-size: 14px; font-weight: 500; letter-spacing: -.005em;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background var(--ease), border-color var(--ease), color var(--ease);
}
.btn:hover { background: var(--sky); border-color: var(--sky); color: var(--ink); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn[disabled]:active { transform: none; }
.btn[disabled]:hover { background: var(--mark); border-color: var(--mark); color: var(--on-mark); }
.btn.ghost {
  background: transparent; color: var(--text); border-color: var(--rule-2);
}
.btn.ghost:hover { background: transparent; border-color: var(--mark); color: var(--text); }
.btn.small { height: 30px; padding: 0 12px; font-size: 13px; }

/* The landing's section label: 11px, wide tracking, upper, warm grey. Used
   here for every pane heading so the two surfaces label things the same way. */
.eyebrow, .pane h2 {
  font-family: var(--sans); font-size: 11px; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
  margin: 0 0 .7rem;
}

/* --- landing --------------------------------------------------------- */

.nav {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.1rem 0; border-bottom: 1px solid var(--line);
}
.brand { font-weight: 650; letter-spacing: -0.02em; }
.brand span { color: var(--ink-faint); font-weight: 450; }

.hero { padding: 5rem 0 3.5rem; }
.hero h1 { font-size: clamp(2.1rem, 5vw, 3.2rem); max-width: 20ch; }
.hero p.lede { font-size: 1.15rem; color: var(--ink-soft); max-width: 54ch; }
.hero .cta { display: flex; gap: .8rem; margin-top: 1.6rem; flex-wrap: wrap; }

.eyebrow {
  font-size: .78rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--ink-faint); font-weight: 600; margin-bottom: .8rem;
}

section.band { padding: 3.5rem 0; border-top: 1px solid var(--line); }
.grid { display: grid; gap: 1.6rem; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
.card {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.3rem; background: var(--shell);
}
.card h3 { font-size: 1rem; }
.card p:last-child { margin-bottom: 0; }
.step-n {
  display: inline-grid; place-items: center; width: 1.7rem; height: 1.7rem;
  border-radius: 50%; background: var(--accent-soft); color: var(--accent);
  font-size: .8rem; font-weight: 700; margin-bottom: .7rem;
}
.rule { list-style: none; padding: 0; margin: 0; }
.rule li {
  padding: .7rem 0 .7rem 1.6rem; border-bottom: 1px solid var(--line);
  position: relative;
}
.rule li:before {
  content: "→"; position: absolute; left: 0; color: var(--accent);
}
.rule li:last-child { border-bottom: 0; }

pre.sample {
  background: var(--shell); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1rem; overflow-x: auto; font-family: var(--mono); font-size: .8rem;
  line-height: 1.5; margin: 0;
}
footer { border-top: 1px solid var(--line); padding: 2rem 0 3rem; color: var(--ink-faint); font-size: .85rem; }

/* --- workspace ------------------------------------------------------- */

/* The bar is the one thing on screen at every moment, so it is the thing that
   has to feel built. Flat paper on flat paper with a hairline under it read as
   a browser toolbar; it now sits a plane above the panes and the actions are
   grouped rather than strung out at even spacing. */
.topbar {
  display: flex; align-items: center; gap: 1rem; justify-content: space-between;
  padding: 0 var(--pad); height: var(--bar); flex: none;
  border-bottom: 1px solid var(--rule);
  background: var(--paper); box-shadow: var(--lift-1);
  position: relative; z-index: 5;
}
/* One group, one rule between the things that make the deck and the things
   that are about you. */
.topbar__actions { display: flex; align-items: center; gap: .5rem; }
.topbar__actions .pop#account { margin-left: .35rem; padding-left: .6rem;
                                border-left: 1px solid var(--rule); }
.brand { display: flex; align-items: baseline; gap: 10px; min-width: 0; text-decoration: none; }
.brand b { font-family: var(--sans); font-weight: 400; font-size: 21px;
           letter-spacing: -.01em; color: var(--text); }
.brand span { font-size: 10px; letter-spacing: .18em; text-transform: uppercase;
              color: var(--muted); white-space: nowrap; }

/* Left rail for the diligences, the deck in the middle, the review panel on
   the right. Fede's ask, and the measurement behind it: on a 1680px window
   the old three-pane split rendered an 89-slide deck at 849px while a form
   you fill in once held 336px permanently. The setup form is a tab now. */
/* Two columns since 18 Aug. The third was a 19rem reference column — notes,
   downloads, gaps, evidence, run log — that Fede said outright was no use to
   him, and taking it out is what gives the slides their width back. Nothing in
   it was deleted: the send control joined the note box already under the
   slide, downloads went to the topbar next to the button that makes them, and
   the reference folds behind one "Run details" sheet. */
/* One column. The rail of diligences lived here and did the grid's job in
   fifteen rems the deck needed more; where you are and how to leave moved to
   the breadcrumb in the top bar. */
.cols {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 0; flex: 1 1 auto; min-height: 0;
}
/* One column, always, since 30 Aug. The notes pane was the second track and
   it took 19rem off the deck for as long as a single note existed — on the
   screen whose entire purpose is a slide being read at a size somebody can
   judge. It is a drawer over the page now (`.notes-pane` below), so nothing
   budgets a track for it and nothing can fall into one.

   The history is worth keeping because it has bitten twice: a grid track with
   no child is not empty space. Both of the rules that used to live here still
   budgeted a first column for the rail of diligences after the rail was
   deleted, and the deck pane fell into it — a 13rem sliver on any window
   under 74rem. If a column is ever added back, add the child in the same
   commit.

   The height is `flex`, not `calc(100vh - 60px)`: `body.app` is the frame and
   the bars are flex siblings, so the arithmetic that had to be kept in step
   with `--bar` by hand is gone. `min-height: 0` is what lets the pane inside
   scroll instead of pushing the grid past the window. */
@media (max-width: 56rem) {
  body.app { height: auto; overflow: auto; }
  .cols { grid-template-columns: 1fr; height: auto; }
}

/* One inset, everywhere, and it is `--pad`.
   There were three: the top bar at `--pad` (18px), a pane at 1.4rem (22px),
   and `#home`/`#dossier` adding 2rem *inside* the pane on top of that (54px).
   So the wordmark, the deck and the grid of diligences each began at a
   different left edge, and the page read as three things stacked rather than
   one screen. Panes and sections now share the bar's edge; a section that
   needs breathing room takes it vertically. */
.pane { padding: var(--pad); border-right: 1px solid var(--rule);
        overflow-y: auto; min-height: 0; }
.pane:last-child { border-right: 0; }

/* Every pane says what it is, in the same 11px tracked label, at the same
   height. Three columns that each began differently is most of why this
   looked assembled rather than designed. */
.pane__head {
  display: flex; align-items: center; justify-content: space-between; gap: .6rem;
  min-height: 30px; margin-bottom: .55rem;
}
.pane__head h2 { margin: 0; }

/* Thin, and only while the pointer is in the pane. A permanent scrollbar in
   each of three columns was three vertical lines the design did not draw. */
.pane, .rail, .notes-pane__list { scrollbar-width: thin; scrollbar-color: transparent transparent; }
.pane:hover, .rail:hover, .notes-pane__list:hover { scrollbar-color: var(--rule-2) transparent; }

/* The label is the quiet half and the value is the loud one; it was the other
   way round — 13.6px grey label over 15px grey text in a hairline box, so a
   filled field and an empty one looked the same at a glance. */
label.field { display: block; margin: 0 0 1.1rem; font-size: 12.5px; font-weight: 500;
              letter-spacing: .01em; color: var(--text-2); }
/* Every text-like input, not just `type=text`. It was the narrow selector for
   as long as the only other one was the token box on the sign-in page, which
   nobody looked at twice — so `type=email` and `type=password` fell through to
   the browser's own control: no width, no border, no focus ring, sitting inline
   beside its label while every field in the workspace was a block. The sign-up
   form made that four fields on the first page a customer ever sees. */
input[type=text], input[type=email], input[type=password], input[type=search],
textarea, select {
  display: block; width: 100%; margin-top: .35rem; padding: .6rem .75rem;
  font: inherit; font-size: 14px; line-height: 1.55;
  color: var(--text); background: var(--paper);
  border: 1px solid var(--rule-2); border-radius: var(--radius);
  transition: border-color var(--ease), box-shadow var(--ease);
}
input[type=text]::placeholder, input[type=email]::placeholder,
input[type=password]::placeholder, textarea::placeholder { color: var(--text-3); }
textarea { resize: vertical; min-height: 4.5rem; }
/* A ring, not an outline drawn inside the border: `outline-offset: -1px` put a
   2px accent line on top of the 1px border and the field appeared to change
   size when you clicked it. */
input:focus, textarea:focus, select:focus {
  outline: none; border-color: var(--text-3);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* A select that is drawn like the inputs beside it. The UA control brought its
   own font, its own height and a system-blue focus ring. */
select {
  appearance: none; padding-right: 2rem; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-3) 50%),
                    linear-gradient(135deg, var(--text-3) 50%, transparent 50%);
  background-position: calc(100% - 1.05rem) 55%, calc(100% - .72rem) 55%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}


/* Square, like everything else. A 999px pill was the only rounded thing on the
   page, which read as a control borrowed from another product. */
.status {
  display: inline-flex; align-items: center; gap: .45rem;
  font-size: 12.5px; height: 30px; padding: 0 .7rem; margin-right: .35rem;
  border-radius: var(--radius); border: 1px solid var(--rule);
  background: var(--card); color: var(--text-2); white-space: nowrap;
}
.dot { width: .5rem; height: .5rem; border-radius: 50%; background: var(--ink-faint); }
/* `status--`, not a bare state class. `deal.status` goes straight into the
   class attribute and one of its values is `storyline`, which collided with
   the storyline pane's own class — see `render()` in app.js. */
.status--running .dot { background: var(--accent); animation: pulse 1.1s infinite; }
.status--done .dot { background: var(--good); }
.status--failed .dot { background: var(--warn); }
/* The one state that means a person is being waited on, in the colour the home
   grid already uses to mean exactly that (`.dot--waiting`). It had no rule, so
   it fell through to `--ink-faint` — the greyest dot on the bar for the only
   status worth interrupting somebody about. Both are `--navy`, which the dark
   block lightens, so the two screens agree in either theme. */
.status--storyline .dot { background: var(--navy); }
@keyframes pulse { 50% { opacity: .25; } }

/* `#draft` was the on-screen report — one editable column, centred to a
   reading measure. That view was removed on 19 Aug ("the report is a file you
   can work on"), and there has been no `id="draft"` in `app.html` since. The
   rule outlived it, and its comment — "same measure as the storyline, same
   centring" — was the only surviving argument for the storyline's centring
   when that came up for review today. A dead rule that still argues for a live
   one is worse than a dead rule. */
.section-block { border-bottom: 1px solid var(--line); padding: 1.1rem 0; }
.section-block h3 { font-size: 1.05rem; margin-bottom: .4rem; }
.section-block textarea { min-height: 6rem; font-size: .95rem; }
.cites { margin: .5rem 0 0; padding: 0; list-style: none; font-size: .8rem; color: var(--ink-soft); }
.cites li { padding: .25rem 0 .25rem .9rem; border-left: 2px solid var(--line); margin-bottom: .2rem; }
.cites .src { color: var(--ink-faint); }

.gap {
  border-left: 3px solid var(--warn); background: var(--warn-soft);
  padding: .6rem .8rem; border-radius: 0 var(--radius) var(--radius) 0; margin-bottom: .6rem; font-size: .88rem;
}
.note { font-size: .82rem; color: var(--ink-soft); padding: .35rem 0; border-bottom: 1px dotted var(--line); }
.dl { display: flex; flex-direction: column; gap: .4rem; margin-bottom: 1.2rem; }
.dl a { font-size: .87rem; }
.badge {
  display: inline-block; font-size: .7rem; padding: .1rem .45rem; border-radius: var(--radius);
  background: var(--accent-soft); color: var(--accent); font-weight: 600; margin-left: .35rem;
}
.empty { color: var(--text-3); font-size: 13.5px; line-height: 1.6; padding: 2rem 0;
         text-align: center; max-width: 32rem; margin: 0 auto; }

/* --- the deck, in the browser ---------------------------------------- */
/* A reading view of the same Deck the .pptx and .ppttc are built from — so
   what gets reviewed is what gets handed over. Deliberately not a pixel copy
   of PowerPoint: pretending to be exact is how someone gets surprised by the
   real file. */

/* Underlined rather than pilled: the landing has no filled chips anywhere,
   and a rule under the live tab is the same drawn-line vocabulary as the
   accent bar under a slide headline. */
/* A row of the frame, not something inside the scrolling pane. It was sticky
   at the top of the pane and pulled out to the edges with negative margins,
   which is the arithmetic you write when a thing is in the wrong box: it is a
   sibling of the pane now, between the top bar and the content, and it simply
   does not move. The whole window belongs to the step you are on. */
.tabs {
  display: flex; align-items: center; gap: 1.2rem;
  flex: none; z-index: 4;
  padding: 0 var(--pad);
  background: var(--paper); border-bottom: 1px solid var(--rule);
}
.tabs[hidden] { display: none; }
.tab {
  border: 0; background: none; font: inherit; font-size: 13.5px; cursor: pointer;
  padding: .55rem 0; color: var(--text-2); position: relative;
  transition: color var(--ease);
}
.tab:hover { color: var(--text); }
.tab.active { color: var(--text); font-weight: 600; }
.tab.active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
  height: 2px; background: var(--mark);
}
.tabs .faint { margin-left: auto; }

/* The setup form is a tab now, not a column. Its layout is further down. */
.setup h2:not(:first-child) { margin-top: 1.8rem; }

.slide-card { margin-bottom: 1.6rem; }
/* Always 1280x720 — the size the .pptx is built at — and scaled to fit
   whatever room it has. It used to be `aspect-ratio: 16/9` on a fluid width
   with rem type, so the preview re-wrapped at every window size and none of
   those wrappings was the file's. A headline that fitted on a wide screen
   overflowed on a narrow one and neither told you what PowerPoint would do.
   (`container-type: inline-size` was set here for that fluid version and
   nothing ever used a `cqw`, so it was doing nothing.)
   The rail already did it this way. Now the stage agrees with the rail, and
   both agree with the file. */
.slide {
  position: relative; width: 1280px; height: 720px; flex: none;
  background: var(--paper);
  /* Re-declaring the tokens is not enough on its own: most text on a slide
     sets no colour and inherits `color` from `body`, which was computed there
     against the workspace's palette long before it reached here. The token has
     to be *used* again at the top of the slide for the inheritance to restart
     from the light value. */
  color: var(--text);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.5rem 1.8rem; display: flex; flex-direction: column;
  transform-origin: top left;
}
/* The box that gives it its room. `--fit` is set by `app.js` from the measured
   width, because dividing a length by a length is not something calc() will do. */
.stage-fit { position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; }
.stage-fit > .slide { transform: scale(var(--fit, 1)); }
.slide.cover { justify-content: center; }
.slide-n {
  position: absolute; top: .5rem; right: .7rem; font-size: .7rem; color: var(--ink-faint);
}
.slide .kicker {
  font-size: .68rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--accent); font-weight: 650; margin-bottom: .35rem;
}
.slide-title { font-size: 1.05rem; line-height: 1.3; margin: 0 0 .5rem; }
.slide.cover .slide-title { font-size: 1.6rem; }
.slide-sub { color: var(--ink-soft); font-size: .9rem; margin: 0; }
.slide-body { margin: .3rem 0 0; padding-left: 1rem; font-size: .82rem; line-height: 1.5; }
.slide-body li { margin-bottom: .2rem; }
.slide-takeaway { font-size: .8rem; color: var(--ink-soft); margin: .5rem 0 0; }
.slide-source {
  margin-top: auto; padding-top: .5rem; font-size: .62rem; color: var(--ink-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.slide .chart { width: 100%; height: auto; max-height: 58%; margin: .2rem 0; }
.slide .chart .grid { stroke: var(--line); stroke-width: 1; }
.slide .chart .axis { fill: var(--ink-faint); font-size: 11px; font-family: var(--sans); }
.legend {
  display: flex; flex-wrap: wrap; gap: .1rem .9rem; font-size: .65rem; color: var(--ink-soft);
}
.legend i { display: inline-block; width: .5rem; height: .5rem; border-radius: 2px; margin-right: .3rem; }

/* The box you write a note in, under the slide it is about. */
.slide-notes { padding: 0; }
.note-row { display: flex; gap: .5rem; align-items: center; }
.note-row input { margin: 0; font-size: 13.5px; }
/* A note is a card: someone wrote it, it is about one thing, and it is either
   open or addressed. As a tinted strip with no edge, twenty of them down a
   column were one blue block. */
/* The card is the control. It had no cursor, no hover and no focus ring while
   being the only way to the slide it is about, which reads as a card that does
   nothing. `--mark` on the left edge is the same "this one" the filmstrip and
   the steps use, so hovering a note and seeing its thumbnail marked is one
   vocabulary rather than two. */
.note-chip {
  display: flex; align-items: baseline; gap: .45rem; font-size: 12.5px; line-height: 1.5;
  background: var(--paper); border: 1px solid var(--rule);
  border-left: 2px solid var(--navy);
  border-radius: var(--radius); padding: .5rem .6rem; margin-bottom: 0;
  box-shadow: var(--lift-1);
  cursor: pointer;
  transition: border-color var(--ease), box-shadow var(--ease), background var(--ease);
}
.note-chip:hover { border-left-color: var(--mark); box-shadow: var(--lift-2); }
/* The note whose slide is on the stage. Without it, jumping to a note in a
   column of nine leaves nothing saying which one you followed — and the reason
   you looked at the column was to work down it. */
.note-chip.here {
  border-left-color: var(--mark); border-left-width: 3px;
  background: var(--card); box-shadow: var(--lift-2);
}
.note-chip:focus-visible { outline: 2px solid var(--sky); outline-offset: 1px; }
.note-chip.done:hover { background: var(--paper); box-shadow: var(--lift-1); }
.note-chip button {
  margin-left: auto; border: 0; background: none; color: var(--ink-faint);
  cursor: pointer; font: inherit;
}
.note-chip button:hover { color: var(--warn); }

details.sources summary {
  cursor: pointer; font-size: .8rem; color: var(--ink-faint); margin-top: .4rem;
}
details.sources[open] summary { margin-bottom: .3rem; }

/* --- the deck browser: a rail of every slide, one on the stage ---------- */

/* The deck view fills the pane and the slide sits in the middle of it. Left to
   size itself the stage sat against the steps with a band of empty paper under
   the note box, because a pane wider than 16/9 of its height leaves the slack
   somewhere and the bottom is the worst place for it. */
.deck { display: grid; grid-template-columns: 9.5rem minmax(0, 1fr); gap: 1.5rem;
        align-items: start; min-height: calc(100dvh - var(--bar) - 5.4rem); }
@media (max-width: 74rem) { .deck { grid-template-columns: 1fr; } .rail { display: none; } }

.rail {
  display: flex; flex-direction: column; gap: .45rem;
  max-height: calc(100dvh - var(--bar) - 5.5rem); overflow-y: auto;
  padding: .15rem .4rem .15rem 0;
  position: sticky; top: 3.1rem;
}

/* The number goes in a gutter beside the thumbnail, not on top of it. It was
   positioned at `left: -.1rem; bottom: -.1rem` — outside its own box, over the
   top-left corner of the slide below — so the filmstrip read as a column of
   misaligned, overlapping cards. A filmstrip is the one place in the product
   where alignment is the entire job. */
.thumb {
  position: relative; cursor: pointer; border-radius: var(--radius);
  display: grid; grid-template-columns: 1.15rem minmax(0, 1fr);
  align-items: center; gap: .5rem;
}
/* Placed, not ordered: the number is written after the face in the DOM
   because it used to be positioned on top of it. */
.thumb-n    { grid-area: 1 / 1; }
.thumb-face { grid-area: 1 / 2; }
/* The thumbnail is the same renderer, scaled — one drawn differently from the
   slide it stands for is a thumbnail you cannot trust. */
.thumb-face {
  width: 100%; aspect-ratio: 16/9; overflow: hidden; background: var(--paper);
  border: 1px solid var(--rule); border-radius: var(--radius);
  transition: border-color var(--ease), box-shadow var(--ease);
}
.thumb:hover .thumb-face { border-color: var(--text-3); }
.thumb-face .slide {
  width: 1280px; height: 720px; transform: scale(0.1); transform-origin: top left;
  border: 0; border-radius: 0; pointer-events: none;
}
.thumb.on .thumb-face { border-color: var(--mark); box-shadow: var(--lift-1); }
.thumb-n {
  font-size: 10.5px; line-height: 1; text-align: right; color: var(--muted);
  font-variant-numeric: tabular-nums; transition: color var(--ease);
}
.thumb:hover .thumb-n { color: var(--text-2); }
.thumb.on .thumb-n { color: var(--text); font-weight: 700; }
.thumb-notes {
  position: absolute; top: -.3rem; right: -.3rem; background: var(--accent); color: #fff;
  font-size: .6rem; font-weight: 700; border-radius: var(--radius); padding: .05rem .35rem;
}

/* --- the stage ---------------------------------------------------------- */
/* One slide, centred, never taller than the room it has. See `--stage-w`. The
   note row is held to the same width so the slide and the box you write about
   it line up on both edges — it used to run the full pane and hang off the
   right of the slide. */
.stage { display: flex; flex-direction: column; align-items: center;
         justify-content: center; gap: .85rem; min-height: 100%; }
.stage > .stage-fit, .stage > .slide-notes, .stage > .empty { width: 100%; max-width: var(--stage-w); }
.stage-fit { box-shadow: var(--lift-2); border-radius: var(--radius); }
.stage .empty {
  aspect-ratio: 16 / 9; display: grid; place-items: center; padding: 2rem;
  border: 1px dashed var(--rule-2); border-radius: var(--radius);
  background: var(--card);
}

/* Themed slide surfaces. The tokens are set per slide from the deck's theme,
   with our own palette as the fallback so an untemplated deck still reads. */
.slide {
  --t-primary: var(--ink); --t-accent: var(--accent); --t-ink: var(--ink);
  --t-muted: var(--ink-soft); --t-paper: var(--paper); --t-line: var(--line);
  --t-heading: var(--sans); --t-body: var(--sans);
  background: var(--t-paper); border-color: var(--t-line);
}
.slide.cover { background: var(--t-primary); }
.slide .kicker { color: var(--t-accent); font-family: var(--t-body); }
.slide-title { color: var(--t-primary); font-family: var(--t-heading); }
.slide.cover .slide-title, .slide.cover .slide-sub { color: #fff; }
.slide-body, .slide-takeaway { color: var(--t-ink); font-family: var(--t-body); }
.slide-takeaway { color: var(--t-muted); }
.slide-rule {
  height: 2px; background: var(--t-accent); width: 3.5rem; margin: .1rem 0 .6rem;
  box-shadow: 3.5rem 0 0 -1px var(--t-line), 20rem 0 0 -1px var(--t-line);
}
.slide-logo {
  position: absolute; top: .7rem; right: 2.2rem; font-size: .55rem; letter-spacing: .12em;
  font-weight: 700; color: var(--t-primary); font-family: var(--t-heading);
}
.slide-footer {
  position: absolute; left: 1.8rem; bottom: .55rem; font-size: .5rem;
  color: var(--t-muted); font-family: var(--t-body);
}
.slide .chart .grid { stroke: var(--t-line); }
.slide .chart .axis { fill: var(--t-muted); }

/* Anything on a slide can be written on. */
/* Clickable elements on a slide are styled once, at `.slide .part` further
   down. This block used to be a second, competing set — `cursor: pointer`
   against `cursor: text`, an 8% accent tint against a 1px ring — written 900
   lines apart and both applying. */
.linky {
  border: 0; background: none; color: var(--accent); cursor: pointer;
  font: inherit; font-size: .85rem; padding: 0 .3rem; text-decoration: none;
  font-weight: 500;
}
.linky:hover { color: var(--navy); }

/* --- the template editor ---------------------------------------------- */

.template-card { background: var(--paper); }
.brand-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: 1.6rem; }
@media (max-width: 60rem) { .brand-grid { grid-template-columns: 1fr; } }
.brand-grid .two { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }

/* The preview scales the real 1280x720 slide down, the way the workspace
   stage and the thumbnail rail both do. It used to rely on `.slide` being
   fluid and shrink the type instead; once every slide became the deck's true
   size, that left a 1280px box inside a 40rem column and 413px of the page
   hanging off the right edge.
   Pure CSS here rather than a ResizeObserver: this preview sits in a grid
   column whose width the browser already knows, and `cqw` reads it. */
.preview { position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; }
.preview .slide { transform: scale(var(--fit, 1)); }

.colour-row { display: grid; grid-template-columns: 1fr 2.2rem 6rem; gap: .5rem; align-items: center;
  font-size: .85rem; color: var(--ink-soft); margin-bottom: .35rem; }
.colour-row .swatch {
  width: 2.2rem; height: 1.9rem; padding: 0; border: 1px solid var(--line);
  border-radius: var(--radius); background: none; cursor: pointer; margin: 0;
}
.colour-row .hex { margin: 0; font-family: var(--mono); font-size: .78rem; padding: .35rem .4rem; }

.layout-card { border: 1px solid var(--line); border-radius: var(--radius); padding: .9rem; margin-bottom: .8rem; }
.layout-head { display: flex; align-items: baseline; gap: .6rem; }
.element-row {
  display: grid; grid-template-columns: 10rem 6rem minmax(0, 1fr) 6.5rem 1.5rem;
  gap: .4rem; align-items: center; margin-bottom: .35rem;
}
.element-row input[type=text], .element-row select { margin: 0; padding: .35rem .5rem; font-size: .85rem; }
.tickbox { display: flex; align-items: center; gap: .3rem; font-size: .78rem; color: var(--ink-faint); }
.tickbox input { margin: 0; }
.map { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: .6rem; }
.map .field { text-transform: capitalize; margin: 0; }

.note-chip.done { background: var(--card); color: var(--text-2);
                  border-left-color: var(--rule-2); box-shadow: none; }
.note-chip .resolution {
  margin-left: auto; font-size: .72rem; color: var(--ink-faint); font-style: italic;
  max-width: 55%; text-align: right;
}
details.history { margin-top: .5rem; }
details.history summary { cursor: pointer; margin-bottom: .4rem; }


/* --- market sizing ----------------------------------------------------- */
.two-up { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.segment-row { display: grid; grid-template-columns: 1fr 1fr 1.6rem 1.2rem; gap: .3rem;
  align-items: center; margin-bottom: .3rem; }
.segment-row input { margin: 0; padding: .35rem .45rem; font-size: .82rem; }
.segment-row .tickbox { font-size: .7rem; }
.sized { font-size: .82rem; margin-top: .6rem; }
.sized div { display: flex; justify-content: space-between; gap: .5rem; padding: .15rem 0;
  border-bottom: 1px solid var(--line); }
.sized b { font-variant-numeric: tabular-nums; }

/* --- the source register ---------------------------------------------- */
.source { border-left: 3px solid var(--line); }
.source.active { border-left-color: var(--good); }
.source.ready { border-left-color: var(--accent); }
.source.planned { border-left-color: var(--ink-faint); }
.source.blocked, .source.broken { border-left-color: var(--warn); }
.source.refused { border-left-color: var(--ink-faint); border-left-style: dashed; }
.source p { font-size: .88rem; }

/* --- the designed page ----------------------------------------------------
   Blocks are positioned absolutely at the geometry `deck/layout.fit` already
   decided, as percentages of the 1280x720 canvas, so the preview scales with
   whatever box it is drawn into and stays the same arrangement as the .pptx.
   There is deliberately no layout logic here: two layout engines would drift,
   and the one that drifts is the one nobody renders to a file. */

.slide .block { overflow: hidden; box-sizing: border-box; }
.slide .block-note { font-size: .58em; color: var(--t-muted); margin-top: .2em; }

.slide .slide-strap {
  color: var(--t-muted);
  font-size: .82em;
  margin: -.15em 0 .35em;
}

/* panels */
.slide .b-panels { display: flex; flex-direction: column; gap: 1.4%; height: 100%; }
.slide .panel {
  position: relative;
  display: flex;
  flex: 1;
  min-height: 0;
  background: #f7f8fa;
}
.slide .panel-rail {
  position: relative;
  width: 21%;
  padding: .5em .6em;
  background: var(--t-primary);
  color: #fff;
  font-weight: 700;
  font-size: .78em;
  line-height: 1.15;
  display: flex;
  align-items: flex-start;
}
.slide .panel-stripe { position: absolute; left: 21%; top: 0; bottom: 0; width: 3px; }
.slide .panel-body {
  flex: 1;
  padding: .45em .8em;
  display: flex;
  align-items: center;
  gap: .6em;
  min-width: 0;
}
.slide .panel-body ul { margin: 0; padding-left: 1em; flex: 1; }
.slide .panel-body li { font-size: .74em; line-height: 1.35; margin: .12em 0; }
.slide .rag { display: flex; flex-direction: column; gap: 3px; flex: 0 0 auto; }
.slide .rag i { width: 7px; height: 7px; border-radius: 50%; display: block; }

/* kpis */
.slide .b-kpis { display: flex; gap: 1.2%; height: 100%; }
.slide .kpi {
  flex: 1;
  background: #f2f4f8;
  border-top: 3px solid var(--t-accent);
  padding: .5em .7em;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}
.slide .kpi b {
  font-size: 1.5em;
  color: var(--t-primary);
  line-height: 1.05;
}
.slide .kpi span {
  font-size: .62em;
  color: var(--t-muted);
  margin-top: .25em;
}

/* table */
.slide .b-table { width: 100%; border-collapse: collapse; font-size: .68em; }
.slide .b-table th {
  background: var(--t-primary);
  color: #fff;
  text-align: left;
  padding: .35em .5em;
}
.slide .b-table td { padding: .3em .5em; border-bottom: 1px solid #e8e8ea; }
.slide .b-table tr:nth-child(even) td { background: #f6f7f9; }

/* A value chain, and who covers which part of it. */
.slide .b-flow { font-size: .66em; }
.slide .b-flow .chain { display: grid; gap: .3em; align-items: start; }
.slide .b-flow .stage {
  background: var(--t-primary);
  color: #fff;
  text-align: center;
  padding: .35em .3em;
  clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 50%, calc(100% - 10px) 100%, 0 100%, 10px 50%);
}
.slide .b-flow .cover { display: flex; align-items: center; gap: .5em; margin-top: .3em; }
.slide .b-flow .cover .who { flex: 0 0 22%; font-weight: 700; }
.slide .b-flow .cover .track { flex: 1; display: grid; gap: .3em; }
.slide .b-flow .cover i { height: 9px; border-radius: 2px; background: transparent; }
.slide .b-flow .cover i.on { background: #9aa3ad; }
.slide .b-flow .cover i.on.first { background: var(--t-accent); }

/* One entity in full. The name band, the attributes down the side, the prose
   beside them — the same three parts the .pptx draws, in the same order. */
.slide .b-profile { font-size: .68em; }
.slide .b-profile .who {
  background: var(--t-primary);
  color: #fff;
  padding: .35em .6em;
  display: flex;
  gap: .5em;
  align-items: center;
}
.slide .b-profile .who .flag {
  font-size: .8em;
  border: 1px solid rgba(255, 255, 255, .5);
  padding: 0 .3em;
  border-radius: 2px;
}
.slide .b-profile .body { display: flex; gap: .8em; margin-top: .5em; }
.slide .b-profile .attrs {
  flex: 0 0 44%;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .15em .5em;
  margin: 0;
}
.slide .b-profile .attrs dt { color: var(--t-muted); }
.slide .b-profile .attrs dd { margin: 0; font-weight: 700; }
.slide .b-profile .b-points { flex: 1; }

/* The register. Same page the .pptx draws: the marker columns are narrow and
   centred, and only the prose column stretches — which is what stops a page of
   dots and ticks from reading as a spreadsheet. */
.slide .b-grid { width: 100%; border-collapse: collapse; font-size: .66em; }
.slide .b-grid th {
  text-align: left;
  padding: .3em .45em;
  color: var(--t-muted);
  border-bottom: 1px solid #dfe3e8;
  font-weight: 600;
}
.slide .b-grid td { padding: .35em .45em; vertical-align: top; }
.slide .b-grid tr:nth-child(odd) td { background: #f7f8fa; }
.slide .b-grid .k-rating,
.slide .b-grid .k-harvey,
.slide .b-grid .k-tick,
.slide .b-grid .k-icon,
.slide .b-grid .k-flag,
.slide .b-grid .k-delta { text-align: center; white-space: nowrap; width: 1%; }
/* The row key is a filled tab, not a cell: it carries the row's pictogram and
   name in reversed type, the way the corpus registers do. Sized to the same
   132px the renderer reserves for it. */
/* The pillar coin: a knockout circle on the panel's own edge. */
.slide .b-panels .panel-rail .badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.5em; height: 1.5em; border-radius: 50%;
  background: var(--t-paper); color: var(--t-primary);
  font-size: .8em; margin-right: .4em; flex: 0 0 auto;
}
/* The insight box's own lockups sit inside it, under the verdict. */
.slide .slide-takeaway p { margin: 0; }
.slide .slide-takeaway .block-strip { margin-top: .4em; }
/* The ornament strip: peers in a row, so equal columns and no wrapping. */
.slide .block-strip { display: flex; gap: 1em; margin-top: .5em; }
.slide .block-strip .lockup { display: flex; align-items: flex-start; gap: .4em; flex: 1 1 0; }
.slide .block-strip .lockup svg { fill: var(--t-accent); flex: 0 0 auto; }
.slide .block-strip .lockup b { display: block; color: var(--t-accent); font-size: 1.15em; }
.slide .block-strip .lockup span { color: var(--t-muted); font-size: .8em; }
.slide .b-grid .k-key { width: 132px; padding: 0; }
.slide .b-grid .k-key .rowkey {
  display: flex; align-items: center; gap: .4em;
  background: var(--t-primary); color: var(--t-paper);
  padding: .45em .5em; margin: 1px 8px 1px 0; min-height: 100%;
}
.slide .b-grid .k-key .rowkey svg { fill: var(--t-paper); flex: 0 0 auto; }
.slide .b-grid th svg { vertical-align: -.15em; margin-right: .3em; }
.slide .b-grid .k-number { text-align: right; white-space: nowrap; width: 1%; }
.slide .b-grid .k-bar { width: 12%; }
.slide .b-grid .tick.yes { color: var(--t-primary); font-weight: 700; }
.slide .b-grid .tick.no { color: #9aa3ad; }
.slide .b-grid .chip {
  display: inline-block;
  padding: .1em .5em;
  border-radius: 999px;
  font-weight: 700;
  background: #eef0f3;
}
.slide .b-grid .chip.up { background: #e6f4ea; color: #1e7d34; }
.slide .b-grid .chip.down { background: #fdeaea; color: #b3261e; }
.slide .b-grid .cellbar {
  display: block;
  height: 8px;
  border-radius: 2px;
  background: #e3e9f7;
}
.slide .b-grid .cellbar i {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--t-accent);
}

/* steps */
.slide .b-steps { display: flex; gap: .6%; height: 100%; align-items: flex-start; }
.slide .step {
  flex: 1;
  background: var(--t-primary);
  color: #fff;
  padding: .5em .6em;
  clip-path: polygon(0 0, 92% 0, 100% 50%, 92% 100%, 0 100%, 6% 50%);
}
.slide .step b { font-size: .76em; display: block; }
.slide .step span { font-size: .62em; opacity: .85; }

/* callout, quote, points */
/* The band was a hardcoded cream, `#fbf7ef`, and it is the reason half the
   filmstrip reads yellow. It was also **wrong**: `house._draw_callout` fills
   this block with `_tint(theme.accent, 0.88)` — the deck's own accent mixed
   88% into white — and paints the rail in the accent solid. Nothing in the
   .pptx is beige. `color-mix(… 12%, #fff)` is that same tint, so the browser
   now shows what the file contains, in whichever colour the firm's theme is
   set to, instead of a beige of its own invention.
   (This rule named `--slide-accent`, a token defined nowhere, and so did about
   forty others. All of them fell back to a hardcoded blue or navy from the day
   they were written, which meant the browser drew every deck in our colours
   while the .pptx drew it in the firm's — on 8 of the 13 decks on the box, a
   real firm's navy and gold read out of their own template. Renamed to
   `--t-accent`, which `slides.js` sets per slide from the theme.) */
.slide .b-callout {
  border-left: 4px solid var(--t-accent);
  background: color-mix(in srgb, var(--t-accent) 12%, #fff);
  padding: .5em .8em;
  font-size: .78em;
  height: 100%;
  display: flex;
  align-items: center;
}
.slide .b-quote { border-left: 3px solid var(--t-accent); padding-left: .7em; }
.slide .b-quote p { font-size: .9em; font-style: italic; margin: 0; }
.slide .b-quote cite { font-size: .65em; color: var(--t-muted); }
.slide .b-points { margin: 0; padding-left: 1.1em; }
.slide .b-points li { font-size: .76em; line-height: 1.4; margin: .2em 0; }

/* The template swap on the landing page. This was a JSON sample and a line
   saying "adding a firm is editing JSON", which is our plumbing on a page
   meant for someone deciding whether to trust us with their deck — and the
   opposite of the promise, which is that they carry on working the way they
   already do. */
.swap { border: 1px solid var(--line); border-radius: var(--radius); padding: 1.2rem 1.3rem; }
.swap-row { display: flex; align-items: center; gap: .9rem; flex-wrap: wrap; }
.swap-in, .swap-out {
  padding: .5rem .8rem; border-radius: var(--radius); font-size: .9rem; font-weight: 600;
}
.swap-in { background: var(--card); color: var(--ink-faint); border: 1px dashed var(--line); }
.swap-out { background: var(--mark); color: var(--on-mark); }
.swap-arrow { color: var(--ink-faint); font-size: 1.2rem; }
.swap-list { margin: 1rem 0 0; padding-left: 1.1rem; color: var(--ink-faint); }
.swap-list li { margin: .35rem 0; font-size: .92rem; line-height: 1.5; }

/* compare */
.slide .b-compare { display: flex; gap: 1.4%; height: 100%; }
.slide .b-compare .col { flex: 1; background: #f7f8fa; border-top: 3px solid var(--t-primary); padding: .5em .7em; min-width: 0; }
.slide .b-compare .tone-good { border-top-color: #1e7a4b; }
.slide .b-compare .tone-bad { border-top-color: #b33a3a; }
.slide .b-compare h4 { margin: 0 0 .3em; font-size: .8em; color: var(--t-primary); }
.slide .b-compare .tone-good h4 { color: #1e7a4b; }
.slide .b-compare .tone-bad h4 { color: #b33a3a; }
.slide .b-compare ul { margin: 0; padding-left: 1em; }
.slide .b-compare li { font-size: .72em; line-height: 1.35; margin: .18em 0; }

/* matrix */
.slide .b-matrix-wrap { position: relative; height: 100%; padding: 0 0 1.1em 1.4em; box-sizing: border-box; }
.slide .b-matrix { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 4px; height: 100%; }
.slide .b-matrix .quad { background: #f4f5f8; padding: .45em .6em; min-width: 0; overflow: hidden; }
/* `house._draw_matrix`: `_tint(_rgb(theme.accent), 0.82)` on a highlighted
   quadrant, and a neutral #f4f5f8 on the rest — which `.quad` above already
   matches. This one was a hardcoded pale blue. */
.slide .b-matrix .quad.on {
  background: color-mix(in srgb, var(--t-accent) 18%, #fff);
  border-top: 3px solid var(--t-accent);
}
.slide .b-matrix .quad b { font-size: .72em; color: var(--t-primary); }
.slide .b-matrix .quad ul { margin: .2em 0 0; padding-left: .9em; }
.slide .b-matrix .quad li { font-size: .62em; line-height: 1.3; }
.slide .ax { position: absolute; font-size: .58em; color: var(--t-muted); }
.slide .ax.x { bottom: 0; right: 0; }
.slide .ax.y { left: 0; bottom: 1.4em; transform: rotate(180deg); writing-mode: vertical-rl; }

/* scorecard */
.slide .b-scorecard { width: 100%; border-collapse: collapse; font-size: .68em; color: var(--t-primary); }
.slide .b-scorecard th { font-weight: 400; color: var(--t-muted); font-size: .9em; padding: .2em; text-align: center; }
.slide .b-scorecard td { padding: .25em; border-bottom: 1px solid #eceef1; }
.slide .b-scorecard .who { font-weight: 700; }
.slide .b-scorecard .sc { text-align: center; }
.slide .b-scorecard .nb { color: var(--t-muted); font-size: .85em; }
.slide .ball { display: inline-block; width: 11px; height: 11px; border-radius: 50%; border: 1px solid currentColor; }

/* assessment: two judgements kept apart — the verdict, and how sure we are */
.slide .b-assessment { display: flex; flex-direction: column; height: 100%; }
.slide .assess-rows { flex: 1; min-height: 0; overflow: hidden; }
.slide .b-assessment table {
  width: 100%; border-collapse: collapse; font-size: .68em; color: var(--t-ink);
}
.slide .b-assessment th {
  font-weight: 400; color: var(--t-muted); font-size: .88em;
  padding: 0 .3em .25em; text-align: left;
}
.slide .b-assessment th.r, .slide .b-assessment th.c { text-align: center; }
.slide .b-assessment td { padding: .3em; border-bottom: 1px solid #eceef1; vertical-align: middle; }
.slide .b-assessment tr:nth-child(odd) td { background: #f7f8fa; }
.slide .b-assessment td.t { width: 26%; }
.slide .b-assessment td.r, .slide .b-assessment td.c { width: 4.6em; text-align: center; }
.slide .b-assessment .badge {
  display: inline-block; min-width: 1.25em; margin: 0 .4em 0 0; padding: .05em 0;
  border-radius: 3px; text-align: center; font-weight: 700; font-size: .85em;
  background: var(--t-primary); color: #fff;
}
.slide .b-assessment .rag { flex-direction: row; justify-content: center; gap: 3px; }
/* The icon is drawn as a shape in the file and named here, same as the panel
   rail — so it needs to read as a tag beside the topic, not run into it. */
.slide .b-assessment .icotag {
  font-style: normal; font-size: .78em; letter-spacing: .04em; text-transform: uppercase;
  color: var(--t-muted); margin-right: .4em;
}
.slide .b-assessment ul { margin: 0; padding-left: 1em; }
.slide .b-assessment li { line-height: 1.35; margin: .1em 0; }
.slide .assess-legend {
  display: flex; flex-wrap: wrap; gap: .1em 1.1em; margin-top: auto; padding-top: .35em;
  font-size: .58em; color: var(--t-muted);
}
.slide .assess-legend span { display: inline-flex; align-items: center; gap: .35em; }
.slide .assess-legend .dot { width: .55em; height: .55em; border-radius: 50%; display: block; }
.slide .assess-legend .ball { width: 9px; height: 9px; color: var(--t-primary); }

/* A component the file draws and this reading view does not. Visible on
   purpose: a block that vanishes silently reads as a broken page. */
.slide .b-undrawn {
  height: 100%; display: flex; align-items: center; justify-content: center;
  border: 1px dashed var(--t-line); border-radius: 4px;
  font-size: .6em; color: var(--t-muted);
}

/* Blocks with no geometry, flowed rather than collapsed to nothing. */
.slide .blocks-flow {
  display: flex; flex-wrap: wrap; align-content: flex-start; gap: .5rem;
  flex: 1; min-height: 0; overflow: hidden;
}
.slide .blocks-flow > .block { height: auto; min-width: 0; }

/* waterfall */
.slide .b-waterfall { display: flex; align-items: flex-end; gap: 2%; height: 100%; }
.slide .wf-col { flex: 1; display: flex; flex-direction: column; height: 100%; text-align: center; }
.slide .wf-v { font-size: .58em; font-weight: 700; }
.slide .wf-track { position: relative; flex: 1; }
.slide .wf-bar { position: absolute; left: 22%; right: 22%; display: block; }
.slide .wf-bar.total { background: var(--t-primary); }
.slide .wf-bar.up { background: #1e7a4b; }
.slide .wf-bar.down { background: #b33a3a; }
.slide .wf-l { font-size: .55em; color: var(--t-muted); margin-top: .3em; }

/* funnel, equation, logos, timeline */
.slide .b-funnel { display: flex; flex-direction: column; align-items: center; gap: 3%; height: 100%; }
.slide .fn { flex: 1; background: var(--t-primary); color: #fff; display: flex; align-items: center; justify-content: center; font-size: .72em; }
.slide .b-equation { display: flex; gap: 1%; align-items: flex-start; justify-content: center; height: 100%; }
.slide .eq-part { flex: 1; text-align: center; }
.slide .eq-value { display: block; font-size: 1.6em; color: var(--t-primary); font-weight: 700; }
.slide .eq-result .eq-value { color: var(--t-accent); }
.slide .eq-label { display: block; font-size: .68em; font-weight: 600; }
.slide .eq-note { display: block; font-size: .56em; color: var(--t-muted); }
.slide .eq-op { align-self: center; color: var(--t-muted); border: 1px solid var(--t-muted); border-radius: 50%; width: 1.4em; height: 1.4em; line-height: 1.35em; text-align: center; font-size: .9em; flex: none; }
.slide .b-logos { display: flex; gap: 2%; align-items: center; height: 100%; }
.slide .mark { flex: 1; background: #f6f7f9; border-top: 2px solid var(--t-accent); padding: .6em .4em; text-align: center; }
.slide .mark b { display: block; font-size: .72em; color: var(--t-primary); }
.slide .mark span { font-size: .58em; color: var(--t-muted); }
.slide .b-timeline { position: relative; display: flex; height: 100%; align-items: center; }
.slide .b-timeline .spine { position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--t-line); }
.slide .ms { flex: 1; text-align: center; position: relative; }
.slide .ms b { display: block; font-size: .64em; color: var(--t-primary); }
.slide .ms i { display: block; width: 8px; height: 8px; background: var(--t-accent); margin: .3em auto; }
.slide .ms span { display: block; font-size: .6em; }
.slide .ms small { display: block; font-size: .54em; color: var(--t-muted); }

/* The rail's mark in the preview. The .pptx draws sixteen icons as native
   shapes; re-drawing those in CSS would be a second implementation to keep in
   step with the first, and the one that drifts is always the one nobody
   renders to a file. The preview shows the country, or names the icon. */
.slide .panel-rail .flagchip,
.slide .panel-rail .icotag {
  position: absolute; right: .5em; bottom: .4em;
  font-style: normal; font-size: .52em; letter-spacing: .04em;
  opacity: .75; font-weight: 600; text-transform: uppercase;
}
.slide .panel-rail .flagchip {
  background: rgba(255, 255, 255, .18); padding: .1em .35em; border-radius: 2px;
}
.slide .slide-notes { margin-top: auto; font-size: .58em; color: var(--t-muted); }
.slide .slide-notes div { line-height: 1.4; }

/* Structural pages. Without these a divider drew as an ordinary slide with
   the section list as bullets under the heading — readable, and not what the
   file shows. */
.slide.divider {
  background: var(--t-primary);
  color: #fff;
  justify-content: center;
  gap: 1.2rem;
  flex-direction: row;
  align-items: center;
}
.slide.divider .divider-main { display: flex; gap: .8rem; align-items: flex-start; flex: 1; }
.slide.divider .chip {
  background: var(--t-accent); color: #fff; font-weight: 700;
  padding: .35em .6em; border-radius: 2px; font-size: 1.1em; line-height: 1;
}
.slide.divider h3 { margin: 0; font-size: 1.9em; }
.slide.divider p { margin: .3em 0 0; opacity: .7; font-size: .85em; }
.slide.divider .divider-toc {
  list-style: none; margin: 0; padding: 0; width: 34%; font-size: .68em;
}
.slide.divider .divider-toc li { padding: .18em 0; opacity: .45; }
.slide.divider .divider-toc li.here {
  opacity: 1; font-weight: 700;
  border-left: 2px solid var(--t-accent); padding-left: .5em;
}
.slide.contents .contents-list {
  list-style: none; margin: 1rem 0 0; padding: 0;
  columns: 2; column-gap: 2rem; font-size: .78em;
}
.slide.contents .contents-list li {
  padding: .35em 0; border-bottom: 1px solid var(--t-line);
  break-inside: avoid;
}

/* The geographic grid: tiles roughly where the countries are. */
.slide .b-geogrid { display: grid; gap: 4%; height: 100%; }
.slide .b-geogrid .tile {
  background: var(--t-primary);
  color: #fff; display: flex; flex-direction: column;
  align-items: center; justify-content: center; min-width: 0;
}
.slide .b-geogrid .tile b { font-size: .7em; }
.slide .b-geogrid .tile span { font-size: .55em; opacity: .85; }

/* Fetched marks and photographs. */
.slide .mark-img { max-width: 70%; max-height: 42%; object-fit: contain; margin: 0 auto .3em; display: block; }
.slide .b-photo { margin: 0; height: 100%; display: flex; flex-direction: column; }
.slide .b-photo-img { max-width: 100%; flex: 1; object-fit: contain; object-position: top; min-height: 0; }
.slide .b-photo figcaption { font-size: .58em; color: var(--t-muted); margin-top: .3em; }

/* --- the marks on a panel ---------------------------------------------- */
/* The preview used to print the icon's name here. See `static/icons.svg` for
   why there are two drawings and what keeps them equal. */

.slide .ico {
  width: 1.15em; height: 1.15em; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.75;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: .85;
}
.slide .flag {
  width: 1.5em; height: 1em; flex: none; border-radius: 1px;
  /* A white band must not bleed into the page — the .pptx outlines these for
     the same reason. */
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .18);
}

/* --- content that does not fit ----------------------------------------- */
/* Measured in the browser after layout, not read off the run note: the note
   lands in the corner of the screen while the cut-off sentence is in the
   middle of it, so nobody ever connected the two. `slides.js::markClipping`. */

.slide .block.clipped { box-shadow: inset 0 -2px 0 0 var(--warn); }
.slide .clip-flag {
  position: absolute; right: 2.2%; bottom: 2.6%; z-index: 3;
  font-family: var(--sans); font-size: 10px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--warn); background: var(--warn-soft);
  border: 1px solid currentColor; border-radius: 1px; padding: .15em .5em;
}
/* A thumbnail is too small to read the flag on, so the rail marks the edge —
   which turns the rail into a map of where the deck is broken. */
.thumb.thumb-clipped::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--warn);
}
.thumb .clip-flag { display: none; }

/* --- explanations, out of the way -------------------------------------- */
/* Every field used to carry a paragraph under it explaining itself. They are
   all worth saying and all of them at once is a wall — the Setup tab was six
   fields and five paragraphs. The text is the same; it waits to be asked for. */

.hint {
  position: relative;
  display: inline-grid; place-items: center; width: 15px; height: 15px;
  margin-left: .4em; vertical-align: 1px; flex: none;
  border: 1px solid var(--rule-2); border-radius: 50%;
  background: none; color: var(--muted); cursor: help; padding: 0;
  font: 600 10px/1 var(--sans); transition: color var(--ease), border-color var(--ease);
}
.hint:hover, .hint:focus-visible { color: var(--text); border-color: var(--text-3); }
/* Beside the icon, not below it: dropped underneath, a long tip covered the
   very control you were reading it to choose.

   **Scoped with `[data-tip]`, which is not decoration.** This rule used to be
   a bare `.hint::after` that re-declared the whole tooltip — and when the
   general `[data-tip]::after` was generalised out of `label.section` on
   26 Aug, the two landed on the same pseudo-element with the *same*
   specificity, 1,200 lines apart. Later wins per property, so what actually
   drew was this rule's `width: 22rem` with the general rule's
   `white-space: nowrap`: 181 characters on one unbreakable line inside a
   352px box, near-white, overflowing onto white paper. A black banner with no
   text in it, which is what it looked like and what it was.

   So: `.hint[data-tip]` beats `[data-tip]` on specificity rather than on
   source order, and it declares only what it changes. Everything else — the
   ground, the ink, the fade, the delay — comes from the one general rule.

   Second instance of this shape in this stylesheet; the first was two
   competing `.part` blocks 900 lines apart. When a tooltip or a highlight
   misbehaves, look for the other rule before editing this one. */
.hint[data-tip]::after {
  left: calc(100% + 10px); bottom: auto; top: 50%; transform: translateY(-50%);
  white-space: normal; width: 22rem; max-width: 46vw;
  padding: .6rem .75rem; font-size: 12.5px; line-height: 1.5; text-align: left;
}
/* A tip you asked for by pointing at a (i) is not one that needs the delay
   that stops tips firing as the pointer crosses a toolbar. */
.hint[data-tip]:hover::after,
.hint[data-tip]:focus-visible::after { opacity: 1; transition-delay: 0ms; }

/* --- setup, across the pane -------------------------------------------- */
/* Held to 34rem it left half the pane blank on any real screen. Two columns
   of groups: what the deck is, and who and what it is built from. */

/* Two columns, held to a width. Left to fill a 1500px pane the fields grew to
   90 characters, which is unreadable, and the two columns still ended 700px
   apart because one of them carried the fifteen section ticks. The ticks are a
   grid now, so the two columns end within a screen of each other. */
/* Fills the pane. It was capped at 74rem, which on a 1792px window is 608px
   of blank paper down the right-hand side — half of what Fede was pointing at
   on 30 Aug when he said the interface should cover the whole screen. Taking
   the side panels out was the other half and it was the half I did first.

   The cap is not replaced by a wider *field*. A 900px box to type a project
   name into is worse than a 450px one; what a wide window buys is another
   column, not a longer line. Three at 88rem and up, two below that, one on a
   laptop — and the columns are the three questions this form asks: what the
   deal is, what you are giving it, what comes out. */
.setup { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
         gap: 0 3.5rem; }
@media (min-width: 88rem) { .setup { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* The rule that used to sit here spanned the second column across the form at
   this width and laid its two drop zones out side by side. Both are gone: the
   documents moved to the data room on 1 Sep and the column is now one small
   card, which has no business being three feet wide. */
@media (max-width: 68rem) { .setup { grid-template-columns: minmax(0, 1fr); } }
.setup-col > h2:first-child { margin-top: 0; }

/* The fold, across the foot of the form on every width. What is in it is
   optional and measured-unused, so it must not take a column from the three
   things that are neither — but it is not hidden either: the summary says
   what is inside and what each is for. */
.setup-more { grid-column: 1 / -1; margin-top: 2.2rem; border-top: 1px solid var(--rule); }
.setup-more > summary {
  list-style: none; cursor: pointer; padding: .9rem 0;
  display: flex; align-items: baseline; gap: .6rem;
  color: var(--text-2); transition: color var(--ease);
}
.setup-more > summary::-webkit-details-marker { display: none; }
.setup-more > summary:hover { color: var(--text); }
/* The disclosure's own mark, so the row reads as something that opens rather
   than as a heading that happens to be clickable. */
.setup-more > summary::before {
  content: "+"; width: .9rem; flex: none;
  font: 500 14px/1 var(--sans); color: var(--muted);
}
.setup-more[open] > summary::before { content: "\2013"; }
.setup-more__title { font-family: var(--sans); font-size: 13.5px; font-weight: 600; color: var(--text); }
/* Three columns again inside it, so opening the fold does not produce one
   very long ribbon of form down the left-hand edge. */
.setup-more__body {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 3.5rem; padding: .4rem 0 1rem;
}
@media (min-width: 88rem) { .setup-more__body { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 68rem) { .setup-more__body { grid-template-columns: minmax(0, 1fr); } }
/* The sections list is the tall one; give it the room the two textareas do
   not need. */
.setup-more__body > .field:last-child { grid-column: auto; }
.setup h2 { padding-bottom: .5rem; border-bottom: 1px solid var(--rule); }

/* --- the review column -------------------------------------------------- */
/* Notes are the job; the rest is reference. Reference folds. */

.review {
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--paper); padding: .85rem;
}
.review-head { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; }

.fold { border-top: 1px solid var(--rule); padding: .7rem 0 0; margin-top: 1.1rem; }
.fold > summary {
  cursor: pointer; list-style: none; user-select: none;
  font-family: var(--sans); font-size: 11px; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
  display: flex; align-items: center; gap: .5rem;
  transition: color var(--ease);
}
.fold > summary:hover { color: var(--text); }
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::after {
  content: "+"; margin-left: auto; font-size: 13px; letter-spacing: 0; line-height: 1;
}
.fold[open] > summary::after { content: "–"; }
.fold > summary .faint { letter-spacing: .04em; text-transform: none; font-weight: 400; }
.fold > *:not(summary) { margin-top: .7rem; }

/* --- the storyline ------------------------------------------------------ */
/* The deck's argument as one column of action titles. Set in the deck's own
   serif at close to the size a headline takes on a slide, because the question
   it answers is "does this read as an argument", and that depends on how the
   sentences sound next to each other. */

/* One column of sentences held to a reading measure — but on the same left
   edge as everything else.
   It was centred, and the argument for that (a reading measure pinned to the
   left of a 1500px pane is the layout of a page that ran out of content) was
   written in the 19 Aug shell pass, committed 22 Aug 15:13. The one-inset rule
   landed at 16:57 the same day, swept `#home` and `#dossier` — which is 62rem
   and left-ragged for exactly the reason the storyline was centred — and
   missed this file. So it is not two live decisions, it is one that did not
   reach here: on a wide screen the wordmark, the tabs and the dossier all
   began at 18px and the storyline began at 420. */
/* Fills the pane. At 52rem it used **46% of a 1792px window** — more blank
   paper than content, on the screen a run stops at and waits for a person.

   The width is spent on structure, not on line length: the headline and what
   the slide will show sit side by side rather than stacked, so the column of
   titles can be read straight down — which is how a partner reads a storyline
   — with its support beside it. Each half keeps its own measure. */
#storyline { padding-bottom: 4rem; }

/* Every screen says what it is, in the same place and the same shape as the
   dossier's. The link is the only answer this screen can give to the question
   it makes people ask — see `renderStoryline`. */
.storyline-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 2rem; margin-bottom: 1.5rem;
}
/* `.pane h2` is the eyebrow and it leaks into any heading inside a pane that
   overrides only the part that looks wrong. Reset what that rule sets. */
.storyline-head h2 {
  margin: 0 0 .2rem; font-family: var(--sans); font-size: 1.35rem;
  color: var(--text); text-transform: none; letter-spacing: -0.021em;
}
.storyline-head p { margin: 0; }
.storyline-head .linkish { flex: none; white-space: nowrap; }
.storyline-section {
  font-family: var(--sans); font-size: 11px; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
  margin: 2rem 0 .6rem; padding-bottom: .4rem; border-bottom: 1px solid var(--rule);
}
.storyline-section:first-of-type { margin-top: 0; }
.storyline-list { list-style: none; margin: 0; padding: 0; }
.storyline-row {
  /* Wraps, because a note left on the line and the box for writing one are
     appended to the row and have to fall *under* it rather than beside the
     cut button. They carry `width: 100%`; this is what lets that mean
     anything. */
  display: flex; flex-wrap: wrap; gap: .85rem; align-items: baseline;
  padding: .35rem .5rem .35rem 0; margin: 0 -.5rem 0 -.5rem;
  border-radius: var(--radius); transition: background var(--ease);
}
/* The row is draggable, editable and clickable, and nothing said so until you
   had already guessed. It lights on hover, once, for the whole row. */
.storyline-row:hover { background: var(--card); }

.storyline-n {
  flex: none; width: 2.1rem; text-align: right; padding: 0; border: 0;
  background: none; cursor: pointer; font: inherit; font-size: 11px;
  color: var(--muted); transition: color var(--ease);
}
button.storyline-n:hover { color: var(--navy); text-decoration: underline; }

.storyline-title {
  font-family: var(--sans); font-weight: 400; font-size: 16px; line-height: 1.4;
  color: var(--text); border-radius: var(--radius);
  padding: .1rem .35rem; margin: -.1rem -.35rem; min-width: 0; flex: 1;
  transition: background var(--ease), box-shadow var(--ease);
}
/* A pointer that changes shape is the cheapest thing a page can do to say
   "you can type here", and 28 rows of dotted underline would be louder than
   the headlines themselves. */
.storyline-title[contenteditable="true"] { cursor: text; }
.storyline-title[contenteditable="true"]:hover {
  background: var(--card); box-shadow: inset 0 -1px 0 0 var(--rule-2);
}
.storyline-title:focus {
  outline: none; background: var(--paper);
  box-shadow: 0 0 0 1px var(--rule-2), 0 0 0 3px var(--accent-soft);
}

/* --- tiered: sets inside sets ------------------------------------------ */
/* Nested, not stacked. The step between TAM and SAM is a definition, not a
   loss — drawn as a funnel it would say the market shrank. */

.slide .b-tiered-wrap { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.slide .b-tiered { flex: 1; min-height: 0; display: flex; }
.slide .b-tiered .tier {
  flex: 1; min-width: 0; min-height: 0;
  display: flex; flex-direction: column; gap: .25em;
  padding: .45em .6em; border-radius: 2px;
}
.slide .b-tiered .tier > b {
  font-size: .62em; line-height: 1.2; font-weight: 650; letter-spacing: -.005em;
}
/* Palest outside, darkest in — the ink follows the narrowing. */
.slide .b-tiered .t0 { background: color-mix(in srgb, var(--t-primary) 14%, #fff); }
.slide .b-tiered .t1 { background: color-mix(in srgb, var(--t-primary) 40%, #fff); }
.slide .b-tiered .t2 { background: color-mix(in srgb, var(--t-primary) 70%, #fff); color: #fff; }
.slide .b-tiered .t3 { background: var(--t-primary); color: #fff; }
.slide .tier-notes {
  flex: none; display: flex; flex-wrap: wrap; gap: .1em .9em;
  margin-top: .35em; font-size: .48em; line-height: 1.35; color: var(--t-muted);
}

/* --- the sections of a document ---------------------------------------- */
/* Ticked boxes rather than a tooltip: the list was already known and reading
   it changed nothing. Unticking is the only control that reduces the cost of
   a run before it runs. */

/* Fifteen of these in one column made the left half of Setup twice the height
   of the right half and pushed the documents boxes off the screen. Two columns
   of ticks, and the whole group reads as one control. */
.sections {
  margin: -.2rem 0 1.4rem; padding: .7rem .85rem;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0 1.2rem;
  background: var(--card); border: 1px solid var(--rule); border-radius: var(--radius);
}
.sections-head {
  grid-column: 1 / -1;
  display: flex; align-items: baseline; justify-content: space-between; gap: .5rem;
  font-size: 11px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); margin-bottom: .55rem;
}
label.section {
  display: flex; align-items: center; gap: .55rem;
  font-size: 13px; line-height: 1.45; color: var(--text);
  padding: .18rem 0; cursor: pointer;
}
label.section.off { color: var(--text-3); text-decoration: line-through; }
/* Drawn, like every other control here. The UA checkbox was the one piece of
   system chrome left on the page — blue, rounded, and a different blue in
   every browser. */
label.section input {
  appearance: none; flex: none; margin: 0; width: 14px; height: 14px;
  border: 1px solid var(--rule-2); border-radius: var(--radius);
  background: var(--paper); cursor: pointer;
  transition: background var(--ease), border-color var(--ease);
}
label.section input:checked {
  background: var(--mark) no-repeat center / 9px 9px;
  border-color: var(--mark);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.7 9 10 3.2' fill='none' stroke='%23FFFFFF' stroke-width='2' stroke-linecap='square'/%3E%3C/svg%3E");
}
/* The tick is drawn into the image, so it cannot take `--on-mark` from a
   variable — the dark ground gets its own. */
@media (prefers-color-scheme: dark) {
  label.section input:checked {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.7 9 10 3.2' fill='none' stroke='%2312161A' stroke-width='2' stroke-linecap='square'/%3E%3C/svg%3E");
  }
}
label.section:hover input:not(:checked) { border-color: var(--text-3); }
label.section input:focus-visible { outline: 2px solid var(--sky); outline-offset: 2px; }

/* --- reordering the storyline ------------------------------------------ */
/* "This belongs under red flags" is an ordinary review note, so a row can be
   dragged anywhere including into another section. A move costs nothing: the
   deck redraws without a model call, and a page keeps its design because
   matching is by headline and a move does not change it. */

/* The row's second control. Faint at rest and present — the storyline gate
   already learned once (26 Aug) that a control at `opacity: 0` on the screen a
   run stops at reads as a screen you cannot edit. */
/* The row's two controls, as glyphs and **on hover only** — Tommaso, 1 Sep:
   *"those icons should only appear on hover over the line"*.

   ⚠ This reverses a decision taken on 26 Aug and pinned in
   `test_the_storyline_gates_controls_are_visible_before_you_touch_them`: a run
   *stops* at this screen, and a reviewer arriving at a list whose controls are
   all invisible reads it as a list they can only look at. That argument was
   about a screen where **four** things were hidden at once — cut, the drag
   handle, and an insert button in every gap — so nothing at all said the deck
   was theirs to edit.

   What makes hiding these two safe now is that the other two stayed: the drag
   handle is on every row at rest, and one insert control stands per section.
   The list still declares itself editable; what it no longer does is print
   two glyphs per row, 56 marks down a 28-slide storyline, to say so twice
   more.

   `:focus-visible` is not decoration here — it is the entire keyboard path to
   a control that no longer exists until a pointer arrives, and there are no
   pointers on a keyboard. */
.storyline-act {
  flex: none; display: grid; place-items: center; width: 24px; height: 24px;
  border: 0; background: none; padding: 0; cursor: pointer; color: var(--text-3);
  border-radius: var(--radius);
  opacity: 0; transition: opacity var(--ease), color var(--ease), background var(--ease);
}
.storyline-act svg { width: 15px; height: 15px; display: block; }
.storyline-row:hover .storyline-act,
/* The row keeps them up while a note is being written into it, or the box
   would vanish under the hand that opened it. */
.storyline-row:focus-within .storyline-act { opacity: 1; }
.storyline-act:hover { color: var(--text); background: var(--rule); }
.storyline-act:focus-visible { opacity: 1; outline: 2px solid var(--accent-soft); outline-offset: 1px; }
.storyline-act:disabled { cursor: not-allowed; opacity: .25; }
.storyline-act:disabled:hover { background: none; color: var(--text-3); }

/* Writing one, in the row rather than in a box somewhere else. */
.storyline-writing { grid-column: 1 / -1; width: 100%; padding: .35rem 0 .1rem 2.95rem; }
.storyline-row .storyline-writing .storyline-ask { width: 100%; }

/* What has been said about this line, under it. Indented to the headline's own
   left edge so it reads as belonging to the row and not to the section. */
.storyline-said {
  grid-column: 1 / -1; width: 100%;
  display: flex; align-items: baseline; gap: .4rem;
  padding: .25rem 0 0 2.95rem; font-size: 12px; line-height: 1.5; color: var(--text-2);
}
.storyline-said.done { opacity: .55; }
.storyline-said .avatar { width: 15px; height: 15px; font-size: 8px; flex: none; }

.storyline-row[draggable="true"] { cursor: grab; }
.storyline-row[draggable="true"]:active { cursor: grabbing; }
.storyline-row.dragging { opacity: .4; }
.storyline-row.over { box-shadow: inset 0 2px 0 0 var(--navy); }
/* The handle is what says "this can be moved", so it cannot wait for the
   pointer to arrive before saying it. Faint at rest, and it takes the row's
   own hover like everything else here. */
.storyline-row[draggable="true"] .storyline-n::before {
  content: "⋮⋮"; margin-right: .3rem; letter-spacing: -2px;
  color: var(--rule); transition: color var(--ease);
}
.storyline-row[draggable="true"]:hover .storyline-n::before { color: var(--rule-2); }

/* --- the pages either side of the workspace ----------------------------- */
/* Templates was written before the workspace took Fede's language
   and carried their own inline styles for everything: a plain-text brand, a
   heading with its size overridden, and `.gap` — the amber "not sourced"
   block — repainted with inline colours to serve as an info callout. Same
   product, three visual dialects. */

.page { max-width: 60rem; margin: 0 auto; padding: 2.4rem 1.5rem 5rem; }
/* The template editor is a form beside a live slide preview, so it needs more
   than a reading column — at 60rem the preview was cut off at the page edge.
   The prose inside still sits at `--measure`, so widening the page does not
   widen the sentences. */
.page.wide { max-width: 78rem; }
.page > h1 { font-size: clamp(26px, 3vw, 34px); margin: 0 0 .5rem; }
.page > .lede {
  max-width: var(--measure); color: var(--text-2); font-size: 15px; margin: 0 0 1.6rem;
}

/* An aside that is information, not a warning. `.gap` is amber because
   something is missing; this is neither missing nor wrong, it is the thing
   you have to know. */
.note-box {
  border: 1px solid var(--rule); border-left: 2px solid var(--mark);
  background: var(--card); border-radius: var(--radius);
  padding: .9rem 1.1rem; margin: 0 0 1.8rem; max-width: var(--measure);
  font-size: 14px; line-height: 1.6;
}
.note-box b { display: block; margin-bottom: .3rem; }
.note-box p { margin: .6rem 0 0; }

/* The brand, wherever it appears. The workspace has the serif mark with an
   eyebrow; these pages had a bare word. */
.topbar .brand + .btn { margin-left: .3rem; }


/* --- what the right column became -------------------------------------- */

/* The deck, next to the button that builds it. */
.pop { position: relative; }
.pop > summary { list-style: none; cursor: pointer; }
.pop > summary::-webkit-details-marker { display: none; }
.pop__menu {
  position: absolute; z-index: 40; right: 0; top: calc(100% + 6px);
  width: 26rem; max-width: 80vw; padding: .8rem .9rem;
  background: var(--paper); border: 1px solid var(--rule-2);
  border-radius: var(--radius); box-shadow: 0 8px 28px rgba(10,15,20,.13);
}
.pop__menu .faint { margin: .6rem 0 0; }
/* Two file names. Nothing to explain, so nothing explaining it. */
.pop__menu--files { width: 9rem; padding: .35rem; }
.pop__menu--files a { display: block; padding: .4rem .5rem; border-radius: var(--radius);
                      font-size: 13.5px; color: var(--text); }
.pop__menu--files a:hover { background: var(--card); color: var(--text); }
.pop__menu--files .dl { gap: 0; margin: 0; }

/* What a section is for, on hover. Above the row rather than beside it: the
   picker is a narrow column and a bubble to its right would leave the pane. */
/* A section heading's tip is a sentence about what the section answers, so it
   is wider and left-set. Everything else it needs is the general rule above. */
label.section[data-tip]::after {
  left: 0; transform: none;
  white-space: normal; width: 24rem; max-width: min(46vw, 24rem);
  padding: .6rem .75rem; font-size: 12.5px; line-height: 1.5; text-align: left;
}

/* A question you cannot miss, directly under the button that asked it. Same
   slot as the banner and the same reasoning: the thing you have to answer
   belongs where you were already looking, not in a modal over the top of the
   deck you are being asked about. Warm rather than red — this is a question,
   not a failure. */
.confirm {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; flex-wrap: wrap;
  padding: .7rem 1.1rem; background: var(--card);
  border-bottom: 1px solid var(--rule-2);
}
.confirm[hidden] { display: none; }
.confirm p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--text-2); }
.confirm b { color: var(--text); font-weight: 600; }
.confirm-do { display: flex; gap: .5rem; flex: none; }
/* No filled button on this row. A confirmation whose costly answer is also the
   most prominent one is the button it was written to slow down, drawn twice. */
.btn.ghost.danger { color: var(--warn); border-color: var(--warn); }
.btn.ghost.danger:hover { background: var(--warn); border-color: var(--warn); color: var(--paper); }

/* An error you cannot miss, directly under the bar it broke. */
.banner {
  padding: .6rem 1.1rem; background: #FBF0EE; color: #7A2E22;
  border-bottom: 1px solid #E8CFC9; font-size: 13px; line-height: 1.5;
}
.banner[hidden] { display: none; }

/* --- the run, on the screen --------------------------------------------- */
/* Under the bar, above everything, for as long as a run is in flight and no
   longer. Five segments because a run has five stages the server announces;
   no percentage because we do not have one and inventing one is the lie a
   person is watching this bar to catch. */
.runbar {
  padding: .55rem 1.1rem .6rem; background: var(--card);
  border-bottom: 1px solid var(--rule);
}
.runbar[hidden] { display: none; }
.runbar__track { display: grid; grid-template-columns: repeat(5, 1fr); gap: 3px; }
.runbar__seg {
  height: 4px; border-radius: 2px; background: var(--rule);
  /* The done colour is set per tone below, so a failed run does not draw four
     confident navy segments behind the word "died". */
}
.runbar__seg.is-done { background: var(--accent); }
.runbar__seg.is-live {
  background: linear-gradient(90deg, var(--rule) 0%, var(--accent) 50%, var(--rule) 100%);
  background-size: 220% 100%; animation: runbar-sweep 1.4s linear infinite;
}
@keyframes runbar-sweep { from { background-position: 120% 0; } to { background-position: -120% 0; } }
/* A moving stripe is the one thing on this screen that never stops, so it is
   the one thing that has to stop for someone who asked for that. The segment
   stays lit — the state is still legible, it just does not travel. */
@media (prefers-reduced-motion: reduce) {
  .runbar__seg.is-live { animation: none; background: var(--accent-soft); }
}
.runbar__say {
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  margin-top: .45rem; font-size: 12.5px; line-height: 1.4;
}
.runbar__say b { font-weight: 600; color: var(--text); }
.runbar__detail { color: var(--text-2); min-width: 0; }
.runbar__age { margin-left: auto; white-space: nowrap; }
/* A stop is an arrival: everything behind it is done and the person is the
   one holding it, so it reads in the accent rather than as a stalled run. */
.runbar--gate { background: var(--accent-soft); border-bottom-color: var(--accent); }
.runbar--gate .runbar__seg.is-done { background: var(--accent); }
.runbar--failed .runbar__seg.is-done,
.runbar--failed .runbar__seg.is-live { background: var(--warn); animation: none; }
.runbar--failed { background: var(--warn-soft); border-bottom-color: var(--warn); }
.runbar--failed .runbar__say b { color: var(--warn); }
/* The way to the raw payload. Only ever drawn on a bar that has gone warn, so
   it takes that colour rather than the page's link grey — it is part of the
   failure, not a footnote beside it. */
.runbar__raw { white-space: nowrap; flex: none; margin-left: .35rem; }
.runbar--failed .runbar__raw { color: var(--warn); }
.runbar__raw[hidden] { display: none; }

/* --- the way on --------------------------------------------------------- */
/* One bar, at the foot of the frame, carrying the one control that moves you
   to the next step. It replaces `Draft the CDD` in the top bar, which meant a
   different thing on every screen it was visible on — and it was visible on
   all of them.

   A row of the frame like the top bar and the step strip, so the pane between
   them is what scrolls and this never moves. The button is the only filled
   thing on the screen at rest: on any step, the question "what do I press" has
   exactly one answer and it is at the bottom right, where it is on every form
   anybody has ever filled in. */
.stepfoot {
  display: flex; align-items: center; gap: 1rem;
  flex: none; min-height: var(--bar); padding: .55rem var(--pad);
  border-top: 1px solid var(--rule); background: var(--paper);
  box-shadow: 0 -1px 0 var(--rule);
  /* Above the notes drawer. The way on is the one control that must never be
     covered, and a drawer over it put two identical black buttons one behind
     the other. */
  position: relative; z-index: 7;
}
.stepfoot[hidden] { display: none; }
/* The sentence between the two is what the step needs said and the screen
   cannot show — never a description of the button beside it. It takes the
   middle and gives it back: a long one must not push the button off the edge. */
.stepfoot__say { flex: 1 1 auto; min-width: 0; font-size: 12.5px; }
.stepfoot__do { flex: none; display: flex; align-items: center; gap: .5rem; }
#foot-back { flex: none; }

/* --- the run, across the whole window ----------------------------------- */
/* Fede, 30 Aug: a full-screen progress bar between the steps. It covers the
   frame — top bar included — because half a workspace visible around the edge
   of a modal is an invitation to click into it, and not clicking into it is
   the entire point.

   Nothing here animates a percentage. There is no percentage: a research wave
   can be four questions or forty. What moves is the live line, which is the
   run telling the truth about where it is. */
.runscreen {
  position: fixed; inset: 0; z-index: 20;
  display: flex; align-items: center; justify-content: center;
  padding: 2rem; background: var(--paper);
}
.runscreen[hidden] { display: none; }
.runscreen__box { width: min(34rem, 100%); }
.runscreen__deal {
  font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  margin: 0 0 .9rem;
}
.runscreen__box h2 { margin: 0 0 .3rem; font-size: 1.5rem; }
.runscreen__detail { margin: 0 0 2rem; color: var(--text-2); min-height: 1.2em; }
/* The five stages of a run, listed rather than drawn as segments. A segment
   strip says how far along you are and nothing else; at this size there is
   room for the stages to say what they are, which is the question somebody
   staring at a ten-minute wait is actually asking. */
.runscreen__stages { list-style: none; margin: 0 0 1.6rem; padding: 0;
                     display: flex; flex-direction: column; gap: .55rem; }
.runscreen__stage {
  position: relative; padding-left: 1.5rem; color: var(--text-3); font-size: 13.5px;
}
.runscreen__stage::before {
  content: ""; position: absolute; left: 0; top: .45em;
  width: 8px; height: 8px; border-radius: 50%;
  border: 1px solid var(--rule-2); background: var(--paper);
}
.runscreen__stage.is-done { color: var(--text-2); }
.runscreen__stage.is-done::before { background: var(--accent); border-color: var(--accent); }
.runscreen__stage.is-live { color: var(--text); font-weight: 600; }
.runscreen__stage.is-live::before {
  background: var(--mark); border-color: var(--mark);
  animation: runpulse 1.4s ease-in-out infinite;
}
@keyframes runpulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) { .runscreen__stage.is-live::before { animation: none; } }
.runscreen__age { margin: 0 0 1.4rem; font-size: 12px; }

/* --- the evidence behind a slide ---------------------------------------- */
/* The ten-second check, under the page it is about. Shut by default: this is
   the control you reach for when a number looks wrong, not something to read
   down. Open, it is the one thing in this product Rogo and Hebbia do not do. */
.slide-evidence { margin-top: .9rem; border-top: 1px solid var(--rule); }
.slide-evidence > summary {
  list-style: none; cursor: pointer; padding: .55rem 0;
  display: flex; align-items: baseline; gap: .5rem;
  font-size: 12.5px; font-weight: 500; color: var(--text-2);
  transition: color var(--ease);
}
.slide-evidence > summary::-webkit-details-marker { display: none; }
.slide-evidence > summary:hover { color: var(--text); }
.slide-evidence > summary::before {
  content: "+"; width: .8rem; flex: none; color: var(--muted); font-weight: 400;
}
.slide-evidence[open] > summary::before { content: "\2013"; }
/* A page with nothing behind it has nothing to open, and says so instead of
   pretending to be a control. */
.slide-evidence.empty > summary { cursor: default; }
.slide-evidence.empty > summary::before { content: ""; width: 0; }

/* Not corroborated by a second source. Colour never alone — the word is the
   signal and the colour is the emphasis, so it survives a screenshot. */
.ev-shaky { color: var(--warn); font-weight: 600; font-size: 11px;
            text-transform: uppercase; letter-spacing: .05em; }

.ev { padding: .7rem 0; border-bottom: 1px solid var(--rule); }
.ev:last-child { border-bottom: 0; }
.ev-claim { margin: 0 0 .4rem; font-size: 13.5px; line-height: 1.5; color: var(--text); }
.ev-value { font-family: var(--sans); font-variant-numeric: tabular-nums; }
.ev.shaky .ev-claim { color: var(--text-2); }
.ev-cite + .ev-cite { margin-top: .5rem; }
/* Theirs, not ours. The claim above is our reading; this is the sentence as it
   was published, and the product's whole promise is telling the two apart. */
.ev blockquote {
  margin: 0 0 .25rem; padding-left: .75rem; border-left: 2px solid var(--rule-2);
  font-size: 12.5px; line-height: 1.55; color: var(--text-2); font-style: italic;
}
.ev-src { font-size: 11.5px; color: var(--muted); }
.src-link { color: var(--navy); text-decoration: none; border-bottom: 1px solid var(--rule-2); }
.src-link:hover { color: var(--text); border-bottom-color: currentColor; }
.src-doc { font-variant-numeric: tabular-nums; }

/* --- notes, over the page ----------------------------------------------- */
/* A review panel you write down, not a bar fighting the slide for the bottom
   of the screen. Notes only: the version of this column that also held
   downloads, gaps, evidence and a run log is the one Fede said was no use.

   A **drawer** since 30 Aug, on the call that took the side panels out of the
   workspace. As a grid column it was permanent from the first note onward and
   it took its 19rem off the deck, which is the artefact being reviewed; over
   the page it costs the deck nothing when it is shut, and when it is open the
   slide is still behind it at full size. */
.notes-pane {
  position: fixed; top: var(--bar); right: 0; bottom: 0; width: 21rem; z-index: 6;
  display: flex; flex-direction: column; background: var(--card);
  /* Clear of the footer, which is drawn above this (`z-index: 7`) so the way
     on stays visible with the drawer open. Without the padding the last note
     scrolls underneath it and cannot be read. */
  padding: var(--pad) 1.1rem calc(var(--bar) + .6rem);
  border-left: 1px solid var(--rule); box-shadow: var(--lift-2);
}
.notes-pane[hidden] { display: none; }
/* The count in the bar is a toggle, so it says which way it is pointing. */
#notes-toggle.on { background: var(--mark); border-color: var(--mark); color: var(--on-mark); }
@media (max-width: 56rem) {
  .notes-pane { position: static; width: auto; box-shadow: none; }
}
.notes-pane__head {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  min-height: 30px; margin-bottom: .55rem;
}
.notes-pane__head h2 { margin: 0; }
.notes-pane__list { flex: 1 1 auto; min-height: 0; overflow-y: auto;
                    display: flex; flex-direction: column; gap: .5rem; }

/* "slide 12 · Chart:" is a label, not prose — breaking it across two lines
   made every note in the column look like it started mid-sentence.

   And it goes *above* the note, not in front of it. In a 20rem column the
   label, the avatar and the remove button took two thirds of the first line
   and left the note itself four words wide, so every remark arrived as a
   narrow ragged stack. Laid out as a comment — who, about what, then what
   they said — it reads at the width of the column. The avatar floats because
   the body of the note is a bare text node with no element to select. */
.notes-pane .note-chip { display: block; position: relative;
                         padding: .5rem 1.5rem .55rem 2.2rem; }
.notes-pane .note-chip .avatar { position: absolute; left: .6rem; top: .55rem; }
.notes-pane .note-chip > .faint {
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-size: 11px; letter-spacing: .04em; margin-bottom: .1rem;
}
.notes-pane .note-chip > button {
  position: absolute; top: .3rem; right: .35rem; margin: 0; line-height: 1;
}
.notes-pane .note-chip .resolution { display: block; margin-top: .35rem; }

/* --- what the remaining tabs are for ----------------------------------- */
.view-lede {
  margin: 0 0 1.2rem; max-width: 46rem;
  font-size: 13.5px; line-height: 1.6; color: var(--text-2);
}

/* The account menu is a list, not a row of buttons. */
.pop__menu--tight { width: 17rem; }
.pop__menu--tight a { display: block; font-size: 13.5px; }
.pop__menu--tight .faint { display: block; margin: .15rem 0 .8rem; font-size: 12.5px; line-height: 1.5; }
.pop__menu--tight form { margin: 0; padding-top: .7rem; border-top: 1px solid var(--rule); }
.pop__menu--tight form .btn { width: 100%; }

/* --- setup, after the deck exists -------------------------------------- */
/* Not greyed into illegibility: it is still the record of what this deck was
   built from, and reading it is the main thing you come here to do. */
.setup-lock {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: 1.3rem;
  padding: .75rem .9rem; background: var(--card);
  border: 1px solid var(--rule-2); border-radius: var(--radius);
}
.setup-lock[hidden] { display: none; }
.setup-lock p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--text-2); }
.setup-lock b { color: var(--text); font-weight: 600; }
/* `background:` here, not `background-color:`. The shorthand resets
   background-image, and the select's arrow is drawn with two gradients — so
   locking the setup silently removed the only thing marking a select as a
   select. */
.setup.locked input, .setup.locked textarea, .setup.locked select {
  background-color: var(--card); color: var(--text-2); cursor: default;
}
.setup.locked label.section { cursor: default; }

/* The two document boxes are not the same kind of thing. */
.legend { max-width: 34rem; margin: -.2rem 0 1rem; line-height: 1.6; }
.drop-hint { margin: .35rem 0 .9rem; font-size: 12.5px; line-height: 1.5; }

/* The report sizes itself to the report; no inner scrollbar to lose text in. */
.section-block textarea { overflow-y: hidden; resize: none; min-height: 4.5rem; }

/* --- the steps ---------------------------------------------------------- */
/* Numbered and in the order the work happens. A step whose artefact does not
   exist yet is disabled and says why on hover, rather than opening an empty
   pane and leaving you to work out whether it is broken or just early. */
.steps .tab i {
  display: inline-grid; place-items: center; width: 17px; height: 17px;
  margin-right: .45rem; vertical-align: -2px;
  border: 1px solid var(--rule-2); border-radius: 50%;
  font: 600 10px/1 var(--sans); font-style: normal; color: var(--muted);
  transition: color var(--ease), border-color var(--ease), background var(--ease);
}
.steps .tab.done i { background: var(--mark); border-color: var(--mark); color: var(--on-mark); }
.steps .tab.active i { border-color: var(--mark); color: var(--text); }
.steps .tab.active.done i { color: var(--on-mark); }
.steps .tab:disabled { opacity: .38; cursor: not-allowed; }
.steps .tab:disabled i { border-style: dashed; }
/* The report is a view of the draft, not a fourth step, so it sits apart. */
.steps .tab--aside { margin-left: 1.4rem; }

/* --- writing on a slide -------------------------------------------------- */
/* This is the whole of "leave a comment on the specific section you want
   changed". The click handling was already there and had no styling, so a
   slide looked inert and every note went on the page as a whole. */
/* Hover and selection, visible on a *slide* rather than on our page.
 *
 * A slide is white when the .pptx is white and near-black when it is a cover
 * or a divider, so feedback keyed to our palette disappears on half the deck:
 * the old ring was 1px of `--sky`, a pale khaki, and the old selected state
 * was a 10% blue wash — both invisible on a navy cover, which is page one.
 * That is most of why this read as "I cannot click anything": on the first
 * three pages of a real deck, either there was nothing to click or clicking
 * it looked like nothing had happened.
 *
 * `currentColor` is the slide's own text colour, so the mark is dark on a
 * white page and light on a dark one without knowing which it is on. */
.slide .part { cursor: text; transition: box-shadow var(--ease), background var(--ease); }
/* The innermost row only. Parts nest since 31 Aug — a bullet inside an
   assessment topic inside a block is three of them — and without the `:has`
   guard the pointer lit all three at once, which said the click would land on
   the outermost when it lands on the innermost. */
.slide .part:hover:not(:has(.part:hover)) {
  box-shadow: 0 0 0 1px color-mix(in srgb, currentColor 38%, transparent);
}
/* A row is a table row or a list item, so the ring needs somewhere to sit. */
.slide tr.part { box-decoration-break: clone; }
.slide li.part { padding-left: 2px; margin-left: -2px; }
.slide .part.selected {
  box-shadow: 0 0 0 2px currentColor;
  background: color-mix(in srgb, currentColor 7%, transparent);
}
/* The whole element, not a hairline down its left edge. An element carrying a
   note has to be findable by scanning the page, which is the job the 2px inset
   was not doing. */
.slide .part.has-note {
  box-shadow: inset 3px 0 0 0 var(--navy);
  background: color-mix(in srgb, var(--navy) 6%, transparent);
}
.slide .part { position: relative; }
.slide .part.has-note:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }

/* An element that has been written on. This was a numbered badge, and the
   number pointed at a list under the slide that no longer exists — so it was
   an index into nothing. What is left is the one thing the mark has to do:
   say *which* elements carry a note, from across the room, without covering
   the element it is marking. Hovering is what produces the words.
   It sits on the left rail rather than in the far corner, and the two are one
   mark. A title runs the full width of the slide: a dot at its right-hand end
   is eleven inches from the words it is about and reads as belonging to
   whatever it happens to be next to. */
/* Bigger than the 8px dot it replaces, and it carries the count.
   Tommaso, 31 Aug: *"see where i left the notes"*. A dot the size of a full
   stop, on a page scaled to 55%, is a speck — it said *that* something was
   marked and could not be found by looking. This reads across the room and
   says how many. */
.note-mark {
  /* The top-left corner, not the middle of the left edge. Centred vertically
     it lands on whatever sits immediately before the element on the same line
     — on a section divider that is the lettered chip, and the pin drew over
     it. The corner is also where every other product puts a comment pin. */
  position: absolute; left: -9px; top: -9px; z-index: 5;
  min-width: 17px; height: 17px; border-radius: 9px; padding: 0 4px;
  display: flex; align-items: center; justify-content: center;
  background: var(--navy); color: #fff;
  font-family: var(--sans); font-size: 10px; font-weight: 700; line-height: 1;
  box-shadow: 0 0 0 2px var(--paper);
  pointer-events: none;
}

/* What was written, over the thing it was written about.
   `position: fixed`, painted from a measurement — see `showNoteCard`. Dark on
   purpose: it lies on top of a picture of a document and must never be read
   as part of it. */
.note-card {
  position: fixed; z-index: 60; max-width: 22rem; min-width: 12rem;
  background: var(--ink); color: var(--bone);
  /* `--ink` and `--paper` are the same value after dark, so a card that ran
     off the edge of the slide onto the page had no edge at all. The hairline
     is invisible in light and is the whole boundary in dark. */
  border: 1px solid rgba(240, 239, 238, .16);
  border-radius: var(--radius); padding: .55rem .7rem;
  box-shadow: var(--lift-2);
  font-size: 12.5px; line-height: 1.5;
  pointer-events: none;
}
.note-card[hidden] { display: none; }

/* The composer. Same card, pinned to the element and typed into, so it has to
   take the pointer — the read-only card must not, or it would eat the hover of
   whatever it is painted over. */
.note-card--compose { pointer-events: auto; width: 20rem; }
.note-card__write {
  width: 100%; margin-top: .5rem; box-sizing: border-box;
  background: rgba(240, 239, 238, .08); color: var(--bone);
  border: 1px solid rgba(240, 239, 238, .22); border-radius: var(--radius);
  padding: .4rem .55rem; font: inherit; font-size: 12.5px;
}
.note-card__write::placeholder { color: rgba(240, 239, 238, .42); }
.note-card__write:focus { outline: none; border-color: rgba(240, 239, 238, .5); }
.note-card--compose .note-card__note:first-of-type { margin-top: 0; }

/* The evidence for the figure you clicked, inside the same card. Shut: you
   open it when a number looks wrong, which is not most of the time. */
.note-card__ev { margin-top: .5rem; border-top: 1px solid rgba(240, 239, 238, .16); }
.note-card__ev > summary {
  list-style: none; cursor: pointer; padding: .4rem 0 .2rem;
  font-size: 11px; letter-spacing: .04em; text-transform: uppercase; opacity: .6;
}
.note-card__ev > summary::-webkit-details-marker { display: none; }
.note-card__ev > summary:hover { opacity: .95; }
.note-card__ev > summary::before { content: "+ "; }
.note-card__ev[open] > summary::before { content: "\2013 "; }
.note-card__fact { padding: .35rem 0; font-size: 12px; line-height: 1.5; }
.note-card__fact p { margin: 0 0 .3rem; }
.note-card__fact blockquote {
  margin: 0 0 .25rem; padding-left: .6rem;
  border-left: 2px solid rgba(240, 239, 238, .22);
  font-style: italic; opacity: .8;
}
/* On the dark card the workspace's link colour disappears. */
.note-card__fact .src-link { color: var(--bone); border-bottom-color: rgba(240, 239, 238, .35); }
.note-card__fact .src-link:hover { border-bottom-color: var(--bone); }
.note-card__note + .note-card__note {
  margin-top: .5rem; padding-top: .5rem;
  border-top: 1px solid rgba(240, 239, 238, .16);
}
.note-card__who {
  display: flex; align-items: center; gap: .35rem; margin-bottom: .2rem;
  font-size: 11px; letter-spacing: .04em; text-transform: uppercase; opacity: .6;
}
.note-card__who .avatar {
  width: 15px; height: 15px; font-size: 8px;
  background: var(--bone); color: var(--ink);
}
.note-card__was { margin-top: .25rem; font-size: 11.5px; font-style: italic; opacity: .6; }
.note-card__note.done .note-card__body { opacity: .6; }

/* Who left the note. Three people share a deal; an anonymous remark reads as
   the product's opinion rather than a colleague's. */
.avatar {
  flex: none; display: grid; place-items: center; width: 19px; height: 19px;
  border-radius: 50%; background: var(--navy); color: #fff;
  font: 600 10px/1 var(--sans); letter-spacing: .02em; text-transform: uppercase;
}

/* The storyline's own gate banner lived here — a bordered box on the screen
   carrying the sentence and the button that got you past it. Both moved to
   `.stepfoot` on 30 Aug: every step's way on is in one place now, and a step
   that also carries its own advance control is two of them to keep in step.
   Deleted rather than left unused; `landing.html` has its own `.steps .gate`,
   scoped, which this unscoped rule was quietly reaching into.
*/


/* The row grows a second line: what the slide is going to show. Reviewing an
   argument means reading the content, not a column of titles. */
.storyline-row { align-items: flex-start; }
.storyline-main { flex: 1; min-width: 0; }
/* Side by side once there is room for both to keep a readable measure.
   Stacked below that, which is what it always was. */
@media (min-width: 76rem) {
  .storyline-main {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    gap: 0 2.5rem; align-items: baseline;
  }
  /* The second line stops being a second line, so the rule that made it read
     as derived rather than as a subtitle is carried by the column instead. */
  .storyline-main > .storyline-body { margin-top: 0; }
}
/* Two or three lines of prose, and nothing else.
   The version before this drew the argument properly — a rail per panel,
   coloured by its verdict, points beneath — and it was wrong for this column.
   Fede: "shouldn't be structured into categories, shouldn't show weird colors,
   but simply be 2/3 lines of text max". The structure is what the slide is
   for; this is read straight down at speed, and nested rails are something you
   stop and parse. Clamped rather than truncated in JS, so a wider window shows
   more of the sentence instead of the same cut-off string. */
/* The second line of a row is *not* a subtitle, and it is the one thing on
   this screen that can be mistaken for one — a title above it that now takes a
   text cursor and lights on hover, and this taking neither.

   It is the evidence the slide will rest on, assembled from the exhibit's own
   points and cut to whole sentences. There is nowhere for an edit to go: those
   points are the drafter's selection out of the evidence pool, so typing over
   them would change the sentence and not the slide. Saying so with a cursor
   is cheaper than saying it in words, and this column already carries enough
   words. */
.storyline-body {
  cursor: default;
  font-family: var(--sans); font-size: 12px; line-height: 1.5;
  color: var(--muted); margin: .1rem 0 0; padding: 0 .35rem .25rem;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  /* Belt and braces: the clamp does the wrapping, and the max-height means a
     browser that ignores it still cannot push the row past two lines. Three
     clamped lines of a slide's full points made every row the same tall block
     and the list ran off the bottom of the pane. */
  max-height: calc(2 * 1.5 * 12px + .25rem);
  overflow: hidden;
}

/* Cut is destructive-looking and reversible, so it is *quiet* — it was
   `opacity: 0`, which is not quiet, it is absent.

   This screen is a gate: a run stops here and waits for a person to cut, move,
   rename or add a page. Measured on a finished deal, three of the four
   controls that let them do any of that were invisible at rest — cut, the drag
   handle and the insert button all at `opacity: 0` — so what a reviewer
   arrives at is a list they can only read, and the way to discover otherwise
   is to sweep a mouse across it. Present, faint, and darker on the row you are
   on: the reader can see the deck is theirs to edit without the page becoming
   a control panel. */
.storyline-cut:hover { color: var(--warn); background: var(--warn-soft); }
/* A cut row does not need its control on show to say it is cut: it is struck
   through and at 45%, which is the state said in the content itself rather
   than in a button beside it. */
.storyline-row.dropped { opacity: .45; }
.storyline-row.dropped .storyline-title { text-decoration: line-through; }
.storyline-act.is-cut:hover { color: var(--text); background: var(--rule); }

/* Between every pair of rows, and there are more gaps than slides.
 *
 * I made this visible at rest for the same reason as `cut` and the drag
 * handle, and it was the wrong call for this one: those are one per row and
 * sit at a row's edge, where this is one per *gap* and carries a label across
 * the column. 28 slides produced 43 buttons reading "add a slide here" — more
 * controls than content, which is what the comment that used to be here
 * warned about and I overrode without weighing it.
 *
 * So: the gap is the target, and it says so by lighting up when the pointer
 * is in it, rather than by keeping a button parked there. Discoverability is
 * carried by `cut` and the handle, which are visible on every row — the list
 * already reads as editable, so a hand looking for where to add finds it. */
.storyline-insert { list-style: none; padding: 0 0 0 2.95rem; margin: 0; }
.storyline-insert-btn {
  display: block; width: 100%; text-align: left; border: 0; background: none;
  cursor: pointer; padding: .18rem 0 .18rem .35rem; margin: 0;
  font-family: var(--sans); font-size: 11px; color: var(--muted);
  opacity: 0; transition: opacity var(--ease), color var(--ease);
}
.storyline-insert-btn::before { content: "+ "; }
.storyline-insert:hover .storyline-insert-btn,
.storyline-insert-btn:focus-visible,
/* Once one is open, the rest stay out of the way but this one is in use. */
.storyline-insert:focus-within .storyline-insert-btn { opacity: 1; }
.storyline-insert-btn:hover { color: var(--accent); }
.storyline-insert-btn:disabled { cursor: default; }

/* The last gap in a section is the one people reach for — "another slide under
   this heading" — so it is the one that does not wait to be found. One per
   section rather than one per gap: fifteen, against forty-three. */
.storyline-list > .storyline-insert:last-child .storyline-insert-btn { opacity: .45; }
.storyline-list > .storyline-insert:last-child:hover .storyline-insert-btn { opacity: 1; }

.storyline-add { display: flex; gap: .5rem; padding: .45rem 0; }
.storyline-add .quiet {
  border: 0; background: none; color: var(--muted); padding: .45rem .5rem;
}
.storyline-add .quiet:hover { color: var(--text); background: none; }
.storyline-ask {
  flex: 1; font-family: var(--sans); font-size: 12px; padding: .45rem .6rem;
  border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper);
  color: var(--text);
}
.storyline-ask.note { flex: .8; }
.storyline-ask:focus { outline: none; border-color: var(--rule-2); box-shadow: 0 0 0 3px var(--accent-soft); }
.storyline-add button {
  flex: none; font-family: var(--sans); font-size: 12px; padding: .45rem .8rem;
  border: 1px solid var(--rule-2); border-radius: var(--radius);
  background: var(--card); color: var(--text); cursor: pointer;
}
.storyline-add button:hover:not(:disabled) { background: var(--accent-soft); }
.storyline-add button:disabled, .storyline-ask:disabled { opacity: .5; cursor: default; }

/* --- the dossier ------------------------------------------------------ */
/* The dossier's stylesheet was here — roughly a hundred and twenty lines of
   it: the four-list switcher, the question groups, a finding and its quote,
   the confidence register and the badges on a question's origin. The screen
   came out of the flow on 30 Aug ("complicata e ridondante rispetto alla
   sintesi della ricerca") and this went with it. `git log -- src/cdd/web/static`
   has all of it if the group changes its mind. `.run-notes` below survives,
   because what a run could not do is now said on the storyline.
*/

/* The workspace's small text buttons — Close, All diligences, the footer's
   back, What the run reported.

   **No underline**, Tommaso 31 Aug: *"useless decoration"*, and he is right
   twice over. An underline is the web's mark for *navigation to a document*,
   and not one of these navigates anywhere — they close a panel, switch a step,
   open a sheet. And there are enough of them on a screen that underlining each
   one draws a row of dashes across a page whose whole design is hairlines.
   What is left carries weight rather than decoration: a shade darker than the
   grey around it, and it goes to full text colour under the pointer, which is
   the only moment a control needs to say it is one. */
.linkish {
  margin-left: .5rem; background: none; border: 0; padding: 0; font: inherit;
  font-size: .78rem; font-weight: 500;
  color: var(--text-2); text-decoration: none; cursor: pointer;
  transition: color var(--ease);
}
.linkish:hover { color: var(--text); }
/* The one place the label is the sentence rather than a control beside one, so
   it does not want the extra left margin every other use is compensating for. */
.stepfoot .linkish, .notes-pane__head .linkish { margin-left: 0; }



/* --- what the run could not do ----------------------------------------- */
/* Warm, not red: a run that gathered nothing is not an error — it succeeded
   at doing nothing, which is worse and reads as calmer. It sits above the
   findings because it is the thing that changes the decision this screen
   exists to make. */
/* A line, not a panel. It was a filled beige block with four sentences in it
   across the top of the screen where the argument is judged — the first thing
   read on the storyline was plumbing. Shut, it is one row with a count on it;
   open, it is the same list it always was.

   The warn colour stays on the mark and leaves the row, because the row is
   permanent furniture on any run that logged anything and a permanent alarm
   is one nobody sees by the third deal. */
.run-notes { margin: 0 0 1.4rem; border-bottom: 1px solid var(--rule); }
.run-notes[hidden] { display: none; }
.run-notes > summary {
  list-style: none; cursor: pointer; padding: .5rem 0;
  display: flex; align-items: baseline; gap: .45rem;
  font-family: var(--sans); font-size: 12.5px; color: var(--text-2);
  transition: color var(--ease);
}
.run-notes > summary::-webkit-details-marker { display: none; }
.run-notes > summary:hover { color: var(--text); }
/* The one thing here that is allowed to be a colour. Small, and it is what
   makes a shut row worth opening. */
.run-notes > summary::before {
  content: ""; width: .42rem; height: .42rem; flex: none; align-self: center;
  border-radius: 50%; background: var(--warn);
}
.run-notes > summary b { font-weight: 600; color: var(--text); }
.run-notes ul { margin: 0; padding: 0 0 .8rem 1.5rem; }
.run-notes li { font-size: .85rem; line-height: 1.55; margin: .25rem 0; color: var(--text-2); }


/* --- home: which deal is waiting for me -------------------------------- */
/* The rail already switches deals. This grid earns its place by answering the
   one thing the rail cannot: a run stops twice, quietly, and with six live
   deals the state that matters most is the one nobody can see. So the deals
   are grouped by who is blocking whom, and "waiting for you" is first. */

/* Fills the pane too. The cards already flow at `auto-fill`, so the only thing
   the cap was doing was leaving 552px of paper blank at 1792px and putting
   four cards on a row that had room for six. */
#home { padding: .5rem 0 4rem; }
.home-head { display: flex; align-items: baseline; justify-content: space-between; }
.home-head h1 { font-family: var(--sans); font-size: 1.5rem; font-weight: 500; margin: 0; }

/* `h1, h2, h3` sets a serif face and its own margins, and it wins on being
   later in the file. These are labels for a group of cards, not headings in a
   document, so they take the sans and their own spacing explicitly. */
#deal-grid .home-group {
  font-family: var(--sans);
  font-size: .72rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--muted); font-weight: 600; margin: 2.2rem 0 .8rem;
  display: flex; align-items: baseline; gap: .5rem;
}
#deal-grid .home-group .count { font-size: .72rem; letter-spacing: 0; text-transform: none; }

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: .8rem; }

/* On the page's own paper, not on `--card`. `--card` is an off-white that is
   right for a pane of reference material and read as a wash under a grid of
   twelve — more so when it was the warm #FFFDF9, less so now it is neutral.
   A card is told apart from the page by its edge and its lift, which is the
   vocabulary the rest of the shell already uses — and unlike a tint it survives dark mode, where `--card` is a shade of
   the ground rather than a shade of the paper. */
.card {
  display: flex; flex-direction: column; gap: .3rem; text-align: left;
  padding: .9rem 1rem 1rem; background: var(--paper); border: 1px solid var(--rule);
  border-radius: var(--radius); font: inherit; color: inherit; cursor: pointer;
  box-shadow: var(--lift-1);
  transition: border-color var(--ease), box-shadow var(--ease);
}
.card:hover { border-color: var(--sky); box-shadow: var(--lift-2); }
/* The state carries a left rail as well as a dot, so which deals are waiting
   survives a black and white print and a colour-blind reader. */
.card--waiting { border-left: 3px solid var(--navy); }
.card--running { border-left: 3px solid var(--muted); }
.card--failed  { border-left: 3px solid var(--warn); }

.card-name { font-weight: 600; font-size: .95rem; }
.card-brief {
  font-size: .8rem; color: var(--text-3); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}
/* The state sits under whatever the card has to say, and the meta sits on the
   floor. A grid row is as tall as its tallest card, so when one deal has a
   brief and its neighbours do not, the short ones used to leave their last
   line floating in the middle of the box. `margin-top: auto` puts every "5m
   ago" on the same line across a row without anyone measuring anything. */
.card-state { font-size: .8rem; color: var(--text-2); margin-top: .35rem; }
.card-meta {
  font-size: .72rem; color: var(--text-3); font-variant-numeric: tabular-nums;
  margin-top: auto; padding-top: .35rem;
}

.dot {
  display: inline-block; width: .42rem; height: .42rem; border-radius: 50%;
  margin-right: .4rem; vertical-align: middle; background: var(--text-3);
}
.dot--waiting { background: var(--navy); }
.dot--running { background: var(--muted); }
.dot--failed { background: var(--warn); }
.dot--done { background: var(--good); }


/* On home the workspace is not there, so neither is anything that acts on a
   deal. A "Draft the CDD" button and a status pill reading "no deal" are the
   workspace's furniture standing in an empty room. */
body.on-home .tabs.steps,
body.on-home .stepfoot,
/* The deck you were last looking at does not follow you back to the grid: its
   notes drawer, its download menu and its run bar all stood beside a list of
   every diligence. See `showHome`. */
body.on-home #notes-pane,
body.on-home #notes-toggle,
body.on-home #take,
body.on-home #runbar,
body.on-home #status { display: none; }

.home-head { margin-bottom: 1.4rem; }
#deal-grid > .home-group:first-child { margin-top: 0; }

/* Where you are, and the way out. */
.crumbs { display: flex; align-items: center; gap: .5rem; font-size: .85rem; margin-left: .4rem; }
.crumb-sep { color: var(--text-3); }
#crumb-name { font-weight: 600; }
body.on-home .crumbs { display: none; }

/* --- the doorway: sign in, sign up, reset ------------------------------- */
/* One narrow column on the page's own paper, for the four pages a person sees
   before they are anybody. Not `.gate` — that is the storyline's stop-and-wait
   banner inside the workspace, and the two are unrelated.

   These pages are documents, not the application: no `body.app`, so they
   scroll, and they inherit the workspace palette so a person who signs in does
   not watch the product change colour under them. */
.doorway {
  max-width: 25rem; padding-top: 12vh; padding-bottom: 4rem;
}
.doorway .brand {
  display: inline-block; font-family: var(--sans); font-size: 22px;
  font-weight: 400; letter-spacing: -.01em; color: var(--text);
  text-decoration: none; margin-bottom: 1.8rem;
}
.doorway h1 {
  font-family: var(--sans); font-size: 1.4rem; font-weight: 500;
  margin: 0 0 .5rem;
}
.doorway .muted { font-size: .9rem; line-height: 1.6; margin: 0 0 1.5rem; }
.doorway form { margin-bottom: 1rem; }
.doorway .btn { width: 100%; justify-content: center; }

/* The one button that carries the page. `--mark` rather than `--ink`, because
   `--ink` is the one colour in the palette that does not move in dark: a
   primary button painted with it is invisible on a dark ground, which is how
   every selected state in this app was wrong until 19 Aug. */
.btn.primary {
  background: var(--mark); border-color: var(--mark); color: var(--on-mark);
  font-weight: 600;
}
.btn.primary:hover { background: var(--navy); border-color: var(--navy); color: var(--paper); }

.doorway-alt {
  font-size: .85rem; color: var(--text-2); margin: 1.2rem 0 0; line-height: 1.7;
}
.doorway-alt .sep { color: var(--rule-2); margin: 0 .4rem; }

/* The token door, folded. It is the rarer way in now and it is not going away:
   two of the three of us, CI and the deploy scripts hold a token and none of
   them has an email address. */
.doorway-token { margin-top: 2.4rem; border-top: 1px solid var(--rule); padding-top: 1rem; }
.doorway-token summary {
  cursor: pointer; font-size: .82rem; color: var(--ink-faint); list-style: none;
}
.doorway-token summary::-webkit-details-marker { display: none; }
.doorway-token summary::before { content: "+ "; }
.doorway-token[open] summary::before { content: "− "; }
.doorway-token summary:hover { color: var(--text); }
.doorway-token form { margin-top: .9rem; }

/* Said where it happened, in the colour of a warning rather than a failure:
   almost every one of these is a typo, and a red box for a typo trains people
   to ignore red boxes. */
.notice {
  font-size: .86rem; line-height: 1.55; color: var(--text);
  background: var(--warn-soft); border: 1px solid var(--warn);
  border-left-width: 2px; border-radius: var(--radius);
  padding: .65rem .8rem; margin: 0 0 1.2rem;
}

/* The page when there is nothing on it yet. It was one grey 13px line under a
   heading in the top-left corner of a blank screen, which reads as a page that
   failed rather than a product waiting. Signup made it the second screen a
   customer ever sees.

   Centred in what is left of the window rather than the whole of it, so the
   heading above it stays where it is on every other visit and the block does
   not jump when the first deal arrives. */
.nothing-yet {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: .8rem; max-width: 30rem; margin: 0 auto;
  min-height: min(58vh, 26rem); justify-content: center;
}
/* `.pane h2` is the 11px tracked eyebrow every pane heading uses, and this
   block lives inside a pane — so overriding the size alone left the words in
   uppercase at 24px with 0.18em of tracking, which reads as a section label
   rather than the one sentence on the page. Reset what that rule sets, not
   just what looks wrong. */
.nothing-yet h2 {
  font-family: var(--sans); font-size: 1.5rem; font-weight: 500; margin: 0;
  color: var(--text); text-transform: none; letter-spacing: -0.021em;
}
.nothing-yet p {
  margin: 0; font-size: .93rem; line-height: 1.65; color: var(--text-2);
}
.nothing-yet .btn { margin-top: .5rem; }
.doorway-back { margin: 2rem 0 0; font-size: .85rem; }
.doorway-back a { color: var(--ink-faint); text-decoration: none; }
.doorway-back a:hover { color: var(--text); }

/* --- finding a diligence ------------------------------------------------- */
/* Sixteen deals on the box, thirteen of them finished, and no way to reach one
   except by reading the grid. The box appears once the grid stops being
   readable at a glance; `renderHome` decides when. */
#deal-filter {
  flex: none; width: 15rem; padding: .4rem .65rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--paper); color: var(--text);
  font: inherit; font-size: .85rem;
  transition: border-color var(--ease), box-shadow var(--ease);
}
#deal-filter::placeholder { color: var(--text-3); }
#deal-filter:focus {
  outline: none; border-color: var(--rule-2); box-shadow: 0 0 0 3px var(--accent-soft);
}
#deal-filter[hidden] { display: none; }

.home-more { display: block; margin: .1rem 0 1.4rem; font-size: .8rem; }

/* --- narrow windows ------------------------------------------------------ */
/* Measured at 768px: `document.scrollWidth` 788 against a 768 viewport, so the
   whole page scrolled sideways. The topbar is one flex row of a wordmark, a
   breadcrumb and five controls totalling 594px, and none of the three could
   give. Nothing here is a phone layout — this product is a deck reviewed on a
   laptop — it is the difference between a split screen being cramped and being
   broken. */
@media (max-width: 60rem) {
  .topbar { gap: .5rem; padding: 0 .7rem; }
  /* The breadcrumb is the one part that can lose width without losing meaning:
     the deal's name is also the first thing on the screen below it. */
  .crumbs { min-width: 0; overflow: hidden; }
  #crumb-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .topbar__actions { min-width: 0; flex-wrap: nowrap; }
  /* "New CDD" is the only control here that is not about the deal in front of
     you, and it is one click away inside the account menu's neighbour. */
  #new-deal { display: none; }
  .steps { overflow-x: auto; scrollbar-width: none; }
  .steps::-webkit-scrollbar { display: none; }
  #deal-filter { width: 10rem; }
}

/* --- the product's own dialogs ------------------------------------------- */
/* Replacing `prompt()` and `confirm()`. See `ui.js` for why a `<dialog>` and
   not a div: the behaviour is native, none of the chrome is.
   `.sheet` is the dialog itself and is only the backdrop's anchor; `.sheet__card`
   is the paper. Keeping them separate means the card can be sized and centred
   without fighting the top layer's default box. */
.sheet {
  border: 0; padding: 0; background: none; max-width: none; max-height: none;
  width: 100%; height: 100%; overflow: hidden;
  place-items: center;
}
/* On `[open]` only. A bare `display: grid` here beats the user-agent's
   `dialog:not([open]) { display: none }`, so a cancelled dialog stayed on the
   page — laid out, visible, and no longer modal. The tests said "closed"
   because `dialog.open` was false, which is the property and not the picture. */
.sheet[open] { display: grid; }
.sheet::backdrop {
  /* `--ink` is not available inside `::backdrop` — it is not a descendant of
     :root for inheritance purposes in every engine — so this is the one place
     the ground colour is written out. */
  background: rgba(11, 7, 4, .42);
  backdrop-filter: blur(2px);
}
.sheet__card {
  width: min(27rem, calc(100vw - 2rem));
  background: var(--paper); color: var(--text);
  border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: var(--lift-2);
  padding: 1.3rem 1.4rem 1.1rem;
  display: flex; flex-direction: column;
}
.sheet__card h2 {
  font-family: var(--sans); font-size: 1.05rem; font-weight: 600;
  letter-spacing: -.01em; color: var(--text);
  margin: 0; text-transform: none;
}
.sheet__detail {
  margin: .4rem 0 0; font-size: .85rem; line-height: 1.5; color: var(--text-2);
}
.sheet__field {
  display: block; margin: 1rem 0 .3rem;
  font-size: .78rem; letter-spacing: .02em; color: var(--text-2);
}
.sheet__card input {
  width: 100%; margin: 0;
  padding: .5rem .65rem; font: inherit; font-size: .95rem;
  border: 1px solid var(--rule-2); border-radius: var(--radius);
  background: var(--paper); color: var(--text);
}
.sheet__card input:focus {
  outline: none; border-color: var(--navy); box-shadow: 0 0 0 3px var(--accent-soft);
}
.sheet__do { display: flex; justify-content: flex-end; gap: .5rem; margin-top: 1.2rem; }

/* Wider, for the one sheet that shows something rather than asking something.
   A provider payload is a single 260-character line of JSON-ish; at the ask
   sheet's 27rem it wraps into a paragraph nobody can find the message in. */
.sheet__card--wide { width: min(44rem, calc(100vw - 2rem)); }
.sheet__verbatim {
  margin: 1rem 0 0; padding: .7rem .8rem; max-height: 46vh; overflow: auto;
  font-family: var(--mono);
  font-size: .76rem; line-height: 1.55; color: var(--text-2);
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--radius);
  /* It arrives as one long line. Wrapped, and broken mid-token where it has
     to be, because a horizontal scrollbar over a request id is a worse read
     than a ragged one. */
  white-space: pre-wrap; overflow-wrap: anywhere;
}

/* No entrance for anyone who has asked not to be moved. */
@media (prefers-reduced-motion: no-preference) {
  .sheet[open] .sheet__card { animation: sheet-in 130ms ease-out; }
  @keyframes sheet-in {
    from { opacity: 0; transform: translateY(4px) scale(.99); }
  }
}

/* --- the product's own tooltip ------------------------------------------- */
/* Replacing `title=`. The browser's tooltip waits about a second, draws in the
   OS font at the OS size in the corner of the pointer, cannot wrap where you
   want it to, cannot be reached from the keyboard and does not exist at all on
   a touch screen — and this product already had a designed tooltip, used on
   the Setup labels, which made every `title=` elsewhere a decision to use the
   browser's instead of ours.
   Generalised from `label.section[data-tip]`, which was the same rule scoped
   to one selector. */
[data-tip] { position: relative; }
[data-tip]::after {
  content: attr(data-tip);
  position: absolute; z-index: 40;
  left: 50%; bottom: calc(100% + 6px); transform: translateX(-50%);
  padding: .3rem .5rem; border-radius: var(--radius);
  background: var(--ink); color: var(--bone);
  /* `--ink` and `--paper` are the same value after dark, so the tip needs an
     edge of its own to sit on the page's own ground. */
  box-shadow: 0 0 0 1px rgba(240, 239, 238, .14), var(--lift-2);
  font: 400 11.5px/1.4 var(--sans); letter-spacing: 0; text-align: center;
  white-space: nowrap; text-transform: none; font-style: normal;
  opacity: 0; pointer-events: none; transition: opacity var(--ease);
}
/* A tip that appears instantly is noise as the pointer crosses a toolbar; one
   that waits a second is the browser's. */
[data-tip]:hover::after,
[data-tip]:focus-visible::after { opacity: 1; transition-delay: 300ms; }

/* Long enough to need a paragraph rather than a label. */
[data-tip][data-tip-wide]::after {
  white-space: normal; width: 18rem; text-align: left; padding: .5rem .65rem;
  line-height: 1.5;
}
/* Below, for anything close enough to the top of the window that above would
   put the tip off screen. */
[data-tip][data-tip-below]::after { bottom: auto; top: calc(100% + 6px); }
/* Hard against the left edge — a tip centred on the first control in a row
   hangs off the side of the pane. */
[data-tip][data-tip-start]::after { left: 0; transform: none; text-align: left; }

/* The doorway's own validation message — see `guardForm`. */
.field-error {
  margin: .35rem 0 0; font-size: .8rem; line-height: 1.45; color: var(--warn);
}
.doorway input[aria-invalid="true"] { border-color: var(--warn); }
.doorway input[aria-invalid="true"]:focus {
  border-color: var(--warn); box-shadow: 0 0 0 3px var(--warn-soft);
}

/* ==========================================================================
   The display register, borrowed from the landing page.

   The landing page has been art-directed and the app has not, and the gap is
   almost entirely one thing: **there is no display scale in the workspace.**
   Everything on it lives between 11px and 24px, so nothing on any screen is
   allowed to be the first thing you see. The landing sets its headline at
   `clamp(44px,6vw,92px)` in the same face at weight 600 with -.014em tracking;
   the workspace's page title is 24px at 500.

   Taken here at *working* intensity rather than hero intensity — this is a
   screen somebody has open all day, not a page they read once. What comes
   across is the vocabulary, not the volume: one display size, the same weight
   and tracking, the same section rhythm, and the two-tone headline the landing
   uses to say a second thing without a second element.
   ========================================================================== */

:root {
  --display-w: 600;
  --display-ls: -.014em;
  /* The landing's own rhythm: room that grows with the window instead of a
     hand-picked margin that is right at one size. */
  --bay: clamp(30px, 4.2vh, 56px);
}

/* The 1240px column this block introduced on 26 Aug is gone. It was a
   deliberate choice then and it is the wrong one against the 30 Aug call: on a
   1792px window it left 552px blank and put four cards on a row with room for
   six, on the screen whose whole job is "which of these is waiting for me".
   The cards are `auto-fill`, so width costs nothing and buys a row. What is
   kept from that pass is the part that was not the cap — the display size, the
   weight and tracking, and the section rhythm that scales with the window. */
#home { padding: var(--bay) 0 6rem; }

/* One line again, so the filter sits on its baseline. `flex-start` and a
   hand-set `margin-top` were both compensation for a two-line headline. */
.home-head { align-items: baseline; margin-bottom: var(--bay); }
.home-head h1 {
  font-family: var(--sans); font-weight: var(--display-w);
  font-size: clamp(32px, 3.3vw, 50px);
  letter-spacing: var(--display-ls); line-height: 1.04;
  margin: 0; text-wrap: balance;
}

#deal-grid .home-group { margin: var(--bay) 0 .9rem; }
#deal-grid > .home-group:first-child { margin-top: 0; }

/* Cards with enough room to be read rather than counted. */
.cards { grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr)); gap: 1rem; }
.card { padding: 1.1rem 1.2rem 1.15rem; gap: .35rem; }
.card-name {
  font-size: 1.05rem; font-weight: var(--display-w); letter-spacing: -.008em;
}
.card-state { font-size: .84rem; }


/* --- the pointer says what a slide is for -------------------------------- */
/* Every element on a slide takes a note, and the pointer was an I-beam, which
   is what a text field looks like. A note cursor says "you can write about
   this thing" before anything is clicked — which is the whole affordance on a
   screen whose elements are otherwise indistinguishable from a picture.
 *
 * Two inks, because a slide is white when the .pptx is white and near-black on
 * a cover or a divider: `.slide.cover` and `.slide.divider` take the light
 * one. Both carry a halo of the opposite colour so the outline never
 * disappears into whatever is behind it. `text` is the fallback for anything
 * that refuses the data URI.
 */
.slide .part {
  cursor: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2222%22%20height%3D%2222%22%20viewBox%3D%220%200%2022%2022%22%3E%3Cpath%20d%3D%22M3.4%203.4h15.2v11.1H9.6L5.3%2018v-3.5H3.4z%22%20fill%3D%22%23FFFFFF%22%20stroke%3D%22%230B0704%22%20stroke-width%3D%221.5%22%20stroke-linejoin%3D%22round%22%2F%3E%3Cpath%20d%3D%22M11%206.6v4.7M8.65%208.95h4.7%22%20stroke%3D%22%230B0704%22%20stroke-width%3D%221.5%22%20stroke-linecap%3D%22round%22%2F%3E%3C%2Fsvg%3E") 4 4, text;
}
.slide.cover .part,
.slide.divider .part {
  cursor: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2222%22%20height%3D%2222%22%20viewBox%3D%220%200%2022%2022%22%3E%3Cpath%20d%3D%22M3.4%203.4h15.2v11.1H9.6L5.3%2018v-3.5H3.4z%22%20fill%3D%22%230B0704%22%20stroke%3D%22%23FFFFFF%22%20stroke-width%3D%221.5%22%20stroke-linejoin%3D%22round%22%2F%3E%3Cpath%20d%3D%22M11%206.6v4.7M8.65%208.95h4.7%22%20stroke%3D%22%23FFFFFF%22%20stroke-width%3D%221.5%22%20stroke-linecap%3D%22round%22%2F%3E%3C%2Fsvg%3E") 4 4, text;
}


/* The mark: Henderson's matrix, Stars filled. One colour, inherited, so it
   is the same file on the ink nav and on a paper doorway. */
.brand .mk { width: 1.02em; height: 1.02em; flex: 0 0 auto; align-self: center; }
.doorway .brand { display: inline-flex; align-items: center; gap: .42em; }
/* --- places, and the data room ------------------------------------------ */
/* Added 1 Sep 2026 for the last of the 30 Aug call's six decisions: templates
   and the data room are their own places, not fields on a form and not a
   setting filed under your own face. */

/* The top-level strip, beside the brand and only on the home screen. Two
   places, so it is two words — a tab bar with two tabs in it would be a lot of
   furniture for a choice that fits on one line. */
/* `margin-right: auto` because the bar is `space-between` with three children:
   without it the strip floats into the middle of an empty bar rather than
   sitting beside the brand, which is what it is a continuation of. */
.places { display: flex; align-items: center; gap: 1.1rem;
          margin-left: .6rem; margin-right: auto; }
.places .place {
  font-size: .85rem; color: var(--text-2); text-decoration: none;
  padding: .15rem 0; border-bottom: 1.5px solid transparent;
  transition: color var(--ease), border-color var(--ease);
}
.places .place:hover { color: var(--text); }
.places .place.is-here { color: var(--text); font-weight: 600; border-bottom-color: var(--mark); }
/* Inside a deal the crumb says where you are, and two navigations in one bar
   is how you end up not reading either.

   `body.app`, not bare `body`. Only the workspace sets `on-home`; the
   templates page is a document page and carries neither class, so the
   unscoped rule hid the strip on the one page whose whole purpose is to be
   one of the two places it names. */
body.app:not(.on-home) .places { display: none; }

/* The way in from Setup. A block, not a link: it is the whole of what used to
   be a column, and a one-line link where two drop zones were reads as though
   the documents have been taken away rather than moved. */
.material {
  display: flex; flex-direction: column; align-items: flex-start; gap: .3rem;
  width: 100%; text-align: left; cursor: pointer;
  padding: 1rem 1.1rem; background: var(--card);
  border: 1px solid var(--rule); border-radius: var(--radius);
  font: inherit; color: var(--text);
  transition: border-color var(--ease), box-shadow var(--ease);
}
.material:hover { border-color: var(--sky); box-shadow: var(--lift-2); }
.material__line { font-weight: 600; font-size: .95rem; }
.material__go { font-size: .82rem; color: var(--text-2); }

/* The place itself.
 *
 * Everything here is a hairline and a column. The version this replaces had
 * two dashed boxes, a two-column split that gave half the page to files
 * nothing reads, and rows two lines tall — so four documents filled the
 * screen and the column that matters, what became of each file, could not be
 * read straight down.
 */
/* One measure for the whole screen, so the heading, the table and the aside
   share a right edge. The pane still fills the window — this is the same
   distinction `test_a_workspace_screen_fills_the_pane` draws for the setup
   form and the storyline: the *screen* does not cap itself, the line of text
   does. Four columns spread over 1990px put a file's size a foot away from
   what became of it, which is the pair you read together. */
.droom-head, .ftable, .ftable__empty, .droom-aside { max-width: 76rem; }
.droom-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 2rem; margin-bottom: 1.4rem;
}
.droom-head h1 {
  font-family: var(--sans); font-size: 1.5rem; font-weight: 500; margin: 0 0 .3rem;
}
/* The (i) rides the heading's baseline rather than its cap height. */
.droom-head h1 .hint { vertical-align: .25em; }
.droom-head .lede { margin: 0; color: var(--text-2); font-size: .88rem; }

/* A real table, so the three columns line up down the page and the widths are
   the browser's problem rather than a guess in rems. `fixed` would need those
   guesses; `auto` lets the outcome column take what the longest sentence in it
   needs and gives the rest to the filename. */
.ftable { width: 100%; border-collapse: collapse; font-size: .88rem; }
.ftable td { padding: .6rem .5rem; border-bottom: 1px solid var(--line); vertical-align: baseline; }
.ftable td:first-child { padding-left: 0; }
.ftable td:last-child { padding-right: 0; }
.frow__name { color: var(--text); overflow-wrap: anywhere; }
.frow__said { color: var(--text-2); white-space: nowrap; }
/* Not a red row and not a rule down its edge — the sentence says what
   happened, and a document that produced nothing is usually a scan we could
   not read, which is a thing to go and look at rather than an alarm. */
.frow--failed .frow__said { color: var(--warn); white-space: normal; }
.frow__size { color: var(--text-3); text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.frow__act { width: 1.6rem; text-align: right; }
.frow__act button {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--text-3); font: inherit; opacity: 0;
  transition: opacity var(--ease), color var(--ease);
}
/* On the row, like the storyline's. A × on every line is a column of crosses
   down a page whose subject is the documents. */
.frow:hover .frow__act button,
.frow__act button:focus-visible { opacity: 1; }
.frow__act button:hover { color: var(--warn); }

.ftable__empty { color: var(--text-3); font-size: .88rem; margin: 1.4rem 0 0; }

/* House style, below and quiet, because nothing reads it yet. */
.droom-aside { margin-top: 3rem; }
.droom-aside h2 {
  display: flex; align-items: center; gap: .1rem;
  font-family: var(--sans); font-size: 11px; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
  margin: 0 0 .2rem; padding-bottom: .5rem; border-bottom: 1px solid var(--rule);
}
.droom-aside h2 .linkish { margin-left: auto; font-size: 11px; letter-spacing: 0; text-transform: none; }
.ftable--quiet td { color: var(--text-2); }

/* The drop target, drawn only while a file is over the window. This is the
   one place a dashed outline earns itself: it is answering a question that
   has just been asked, rather than sitting on the page asking one. */
.droom-drop {
  position: fixed; inset: var(--bar) 0 0 0; z-index: 40;
  display: grid; place-items: center; pointer-events: none;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
}
.droom-drop[hidden] { display: none; }
.droom-drop span {
  padding: 2rem 3rem; border: 1px dashed var(--accent); border-radius: var(--radius);
  background: var(--accent-soft); color: var(--text);
  font-family: var(--sans); font-size: .95rem;
}

/* --- storyline: a column you read, and glyphs you press ------------------ */
/* 1 Sep. Tommaso: the screen was confusing and "lots of text is never user
   friendly". Three of the four fixes are subtraction; this one is a measure. */

/* On a 1990px window the headline sat at the left edge, its supporting
   sentence 940px away and the controls 960px past that — one row spread over
   two feet of screen, read as three separate things rather than as a line.
 *
 * ⚠ The cap is on the **row**, not on the screen, and the difference is a
 * decision rather than a detail. `#storyline { max-width }` is what I reached
 * for first and it is exactly what
 * `test_a_workspace_screen_fills_the_pane` refuses: Fede's 30 Aug call is that
 * a screen covers the window, measured — the storyline used 46% of a 1792px
 * one. That test's own words are that line length is held *at the field*, the
 * way `.setup` answers a wide window with a third column instead of a wider
 * box. This is the same answer: the pane still fills the window, and the two
 * columns of prose inside it stop growing once they are long enough to read. */
.storyline-main { max-width: 76rem; }


/* --- the account, as a face -------------------------------------------- */
/* It was the word `tommaso` and a caret in a bordered button, sitting in a bar
   beside three other bordered buttons that are all *verbs* — so the one
   control that is not an action looked like a fourth one. A round monogram is
   the shape every tool puts an account in, which is the argument for it: it
   needs no label to be found. Tommaso, 1 Sep.

   `.avatar` is the same circle the note chips and the storyline remarks
   already draw an author with, so a person is one shape everywhere in the
   product. Bigger here, because this one is a target for a pointer. */
.acct-face {
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: 50%; background: var(--navy); color: var(--paper);
  font: 600 11px/1 var(--sans); letter-spacing: .02em; text-transform: uppercase;
  overflow: hidden;
}
.acct-face img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pop#account > summary.acct {
  border: 0; background: none; padding: 0; box-shadow: none;
  display: grid; place-items: center; border-radius: 50%;
  transition: box-shadow var(--ease);
}
.pop#account > summary.acct:hover { background: none; box-shadow: 0 0 0 3px var(--rule); }
.pop#account[open] > summary.acct { box-shadow: 0 0 0 3px var(--rule-2); }
/* The menu is anchored to a 26px control now, not a 90px one, so it needs a
   width of its own or it comes out as narrow as its trigger. */
.pop#account .pop__menu { min-width: 12rem; }
.acct-who {
  display: block; padding: .1rem .1rem .5rem; margin-bottom: .4rem;
  border-bottom: 1px solid var(--rule);
  font-family: var(--sans); font-size: 12.5px; color: var(--text);
}
