/* Echelon console.
   Third design, and the first one built as an instrument rather than a page.
   The register of tall editorial rows is gone: this is a dense operator surface,
   a table you can sort, a board you can drag, one record panel, one palette.

   Rules that survive from the mark:
     1. one ground, four depths: base, surface, raised, float
     2. gold marks the number the quarter turns on, and nothing else
     3. every state change is animated once, briefly, and never replayed
*/

@font-face{
  font-family:"Playfair Display";font-style:normal;font-weight:400 900;
  font-display:swap;src:url("/lib/fonts/PlayfairDisplay.ttf") format("truetype");
}
@font-face{
  font-family:Inter;font-style:normal;font-weight:100 900;
  font-display:swap;src:url("/lib/fonts/Inter.ttf") format("truetype");
}

:root{
  --base:#060B14;
  --panel:#0B1220;
  --raised:#101A2C;
  --float:#16223A;
  --line:rgba(226,236,250,.075);
  --line-2:rgba(226,236,250,.14);
  --ink:#ECF2FA;
  --mute:#9FB0C7;
  --dim:#67788F;
  --gold:#C7A86D;
  --gold-soft:rgba(199,168,109,.13);
  --gold-line:rgba(199,168,109,.42);
  --late:#E08B81;
  --late-soft:rgba(224,139,129,.13);
  --shadow:0 1px 2px rgba(0,0,0,.5),0 18px 46px -18px rgba(0,0,0,.75);
  --shadow-s:0 1px 2px rgba(0,0,0,.4);
  --sans:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  --serif:"Playfair Display",Georgia,serif;
  --r:10px;
  --r-s:7px;
  --pad:12px;
  --side:250px;
  --ease:cubic-bezier(.22,1,.36,1);
  --spring:cubic-bezier(.34,1.4,.5,1);
  --fast:.16s;
  --mid:.28s;
  color-scheme:dark;
}

[data-theme="light"]{
  --base:#F1F4F8;
  --panel:#FFFFFF;
  --raised:#F7F9FC;
  --float:#FFFFFF;
  --line:rgba(11,18,32,.09);
  --line-2:rgba(11,18,32,.16);
  --ink:#0B1220;
  --mute:#54657E;
  --dim:#8494AB;
  --gold:#8F7233;
  --gold-soft:rgba(143,114,51,.1);
  --gold-line:rgba(143,114,51,.34);
  --late:#B4443A;
  --late-soft:rgba(180,68,58,.09);
  --shadow:0 1px 2px rgba(11,18,32,.06),0 18px 40px -20px rgba(11,18,32,.24);
  --shadow-s:0 1px 2px rgba(11,18,32,.06);
  color-scheme:light;
}

/* pseudo-elements too. `*` does not match them, so a ::after carrying a border
   was sized content-box while everything around it was border-box, which is how
   the timeline's markers came to sit beside the rail instead of on it. */
*,*::before,*::after{box-sizing:border-box}
/* an author display rule outranks the browser's [hidden], so an element styled
   flex and toggled hidden stays laid out and keeps swallowing clicks */
[hidden]{display:none !important}
html,body{margin:0;height:100%}
body{
  background:var(--base);color:var(--ink);font-family:var(--sans);
  font-size:13.5px;line-height:1.5;-webkit-font-smoothing:antialiased;
  overflow:hidden;
}
button,input,textarea,select{font:inherit;color:inherit}
/* The open list of a native select, which is drawn by the platform and not by
   this stylesheet.
 *
 * Chrome paints that popup from the select's own computed background and
 * colour. Every select in the panel is transparent by design — `background:none`
 * on a ledger row, `background:var(--raised)` on a field — so the popup fell
 * back to the platform's white while the options inherited `--ink`, which is
 * near-white: the list read as blank with one blue row wherever the pointer
 * happened to be. `color-scheme` on `:root` does not reach it.
 *
 * Stated on the option itself, so it holds in both themes and in every select.
 * The composer carried a copy of this rule and was the only control that did.
 */
option{background:var(--float);color:var(--ink)}
/* the placeholder row is disabled, and a disabled option that is the same
   colour as a real one is a choice you try to pick */
option:disabled{color:var(--dim)}
button{font-feature-settings:"tnum" 1}
::selection{background:var(--gold);color:var(--base)}
:focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:3px}

::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:var(--line-2);border-radius:20px;border:3px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:var(--dim);background-clip:padding-box;border:3px solid transparent}
::-webkit-scrollbar-track{background:transparent}

.lab{
  margin:0;font-size:10px;font-weight:500;letter-spacing:.14em;
  text-transform:uppercase;color:var(--dim);
}
kbd{
  font:inherit;font-size:10px;line-height:1;padding:3px 5px;border-radius:4px;
  border:1px solid var(--line-2);background:var(--raised);color:var(--dim);
}
.keys{display:inline-flex;align-items:center;gap:4px;color:var(--dim)}
.keys kbd{margin:0}
.grow{flex:1}
svg{display:block;flex:none}

/* the shell.
   Nothing is edge to edge. The rail and the header are surfaces resting on the
   ground with a gap around them, the same way every card in the working column
   already sat. */
.app{
  display:grid;grid-template-columns:var(--side) minmax(0,1fr);
  gap:var(--pad);padding:var(--pad);height:100vh;height:100svh;
}
html.side-closed{--side:70px}

/* sidebar */
.side{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow-s);overflow:hidden;
  display:flex;flex-direction:column;min-height:0;
  transition:width var(--mid) var(--ease);
}
/* No rule under the mark and none over the meter. The rail is one surface, and
   a hairline across it at each end cut it into three cards stacked inside a
   fourth. What separates the head, the sections and the foot is space and what
   sits in them. */
.side-head{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  height:58px;padding:0 14px 0 18px;flex:none;
}
.brand{display:flex;align-items:center;gap:.7rem;text-decoration:none;color:inherit;min-width:0}
.bars{display:flex;flex-direction:column;gap:2.5px;flex:none}
.bars i{display:block;height:2.5px;width:22px;background:var(--ink);border-radius:1px;transition:transform .45s var(--ease)}
.bars i:nth-child(3){background:var(--gold)}
@media (hover:hover){
  .brand:hover .bars i:nth-child(2){transform:translateX(4px)}
  .brand:hover .bars i:nth-child(3){transform:translateX(8px)}
}
.brand-name{
  font-size:12px;font-weight:600;letter-spacing:.28em;text-transform:uppercase;
  white-space:nowrap;overflow:hidden;
}
html.side-closed .brand-name,
html.side-closed .who-t,
html.side-closed .meter-top,
html.side-closed .meter-num,
html.side-closed .track,
html.side-closed .meter-dots,
html.side-closed .meter-note{display:none}
/* Collapsed, the objectives block is the mark and nothing else. Everything it
   was showing, cramped into 70px, is in the button's title instead. */
.meter-ico{display:none}
html.side-closed .meter-ico{
  display:grid;place-items:center;height:26px;color:var(--dim);
  transition:color var(--fast) var(--ease);
}
html.side-closed .meter:hover .meter-ico{color:var(--ink)}
html.side-closed .meter.u-due .meter-ico{color:#C98A2E}
html.side-closed .meter.u-late .meter-ico{color:#C4553D}
html.side-closed .meter.u-done .meter-ico{color:var(--gold)}
/* The inset edge marker is most of the signal at this width, so it earns a
   little more of it. Named colours, not currentColor: on .meter that resolves
   to the inherited text colour, which painted the marker white. */
html.side-closed .meter.u-due{box-shadow:inset 3px 0 0 #C98A2E}
html.side-closed .meter.u-late{box-shadow:inset 3px 0 0 #C4553D}
/* collapsed, the meter keeps its number. A bare progress track with no figure
   and no label reads as a fragment of something that failed to render. */
html.side-closed .side-head{padding:0;justify-content:center}
html.side-closed .nav-lab{display:none}
html.side-closed .nav-b{justify-content:center;padding:0}
html.side-closed .nav-b .n-name,html.side-closed .nav-b .n-count{display:none}
html.side-closed .who{justify-content:center}
html.side-closed .who-face{flex:none;justify-content:center;padding:4px}
html.side-closed .who .iconb{display:none}
html.side-closed .meter-face{padding:10px 6px}
html.side-closed .meter-edit{display:none}

.iconb{
  display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:30px;height:30px;border-radius:var(--r-s);border:1px solid transparent;
  background:none;color:var(--dim);cursor:pointer;
  transition:background var(--fast) var(--ease),color var(--fast) var(--ease),border-color var(--fast) var(--ease);
}
.iconb:hover{background:var(--raised);color:var(--ink);border-color:var(--line)}
.iconb:active{transform:scale(.94)}
/* the same button, carrying two letters instead of a glyph */
.langb{
  flex:none;height:30px;min-width:34px;padding:0 8px;border-radius:var(--r-s);
  border:1px solid var(--line);background:var(--raised);color:var(--mute);cursor:pointer;
  font-size:11px;font-weight:600;letter-spacing:.08em;
  transition:color var(--fast) var(--ease),border-color var(--fast) var(--ease);
}
.langb:hover{color:var(--ink);border-color:var(--line-2)}
.langb:active{transform:scale(.94)}

.nav{flex:1;min-height:0;overflow:auto;padding:8px 12px 16px}
.nav-lab{padding:0 8px 8px}
/* the second group and any after it. The sections you work in and the ones that
   describe the firm are not the same kind of thing, and a gap says so without
   another rule across the rail. */
.nav-lab~.nav-lab{padding-top:18px}
.nav-b{
  position:relative;display:flex;align-items:center;gap:11px;width:100%;
  padding:0 10px;height:36px;margin-bottom:2px;border:0;border-radius:var(--r-s);
  background:none;color:var(--mute);cursor:pointer;text-align:left;
  transition:background var(--fast) var(--ease),color var(--fast) var(--ease);
}
.nav-b svg{opacity:.75;transition:opacity var(--fast) var(--ease)}
.nav-b:hover{background:var(--raised);color:var(--ink)}
.nav-b .n-name{flex:1;font-size:13px;font-weight:450;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nav-b .n-count{
  font-size:11px;font-weight:500;color:var(--dim);background:var(--raised);
  border-radius:20px;padding:1px 7px;min-width:22px;text-align:center;
  transition:background var(--fast) var(--ease),color var(--fast) var(--ease);
}
.nav-b[aria-current="true"]{background:var(--raised);color:var(--ink)}
.nav-b[aria-current="true"] svg{opacity:1;color:var(--gold)}
.nav-b[aria-current="true"] .n-count{background:var(--gold-soft);color:var(--gold)}
.nav-b::before{
  content:"";position:absolute;left:-12px;top:9px;bottom:9px;width:2px;border-radius:0 2px 2px 0;
  background:var(--gold);transform:scaleY(0);transform-origin:50% 50%;
  transition:transform var(--mid) var(--spring);
}
.nav-b[aria-current="true"]::before{transform:scaleY(1)}

.side-foot{flex:none;padding:12px;display:grid;gap:8px}

/* The meter, second design. It was a bordered card with the figure tucked into
   the top right corner at 17px, which is the one number the quarter turns on
   set smaller than a table cell. The number is now the subject: display serif,
   gold, reading against the target rather than beside a label. Nothing boxes
   it, because the rail no longer draws rules at either end and a card down here
   would have been the only one left. */
.meter{position:relative;display:grid}
.meter-face{
  display:block;width:100%;text-align:left;cursor:pointer;
  background:none;border:0;border-radius:var(--r);padding:10px 12px 12px;
  transition:background var(--fast) var(--ease);
}
.meter-face:hover{background:var(--raised)}
.meter-edit{
  position:absolute;top:6px;right:6px;width:26px;height:26px;
  opacity:0;transition:opacity var(--fast) var(--ease);
}
.meter:hover .meter-edit,.meter-edit:focus-visible{opacity:1}
.meter-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.meter-num{
  display:flex;align-items:baseline;gap:1px;margin-top:2px;
  font-family:var(--serif);font-variant-numeric:tabular-nums;line-height:1.05;
}
.meter-num b{font-size:27px;font-weight:500;color:var(--gold);letter-spacing:-.01em}
.meter-num i{font-style:normal;font-size:16px;color:var(--dim)}
/* the goal is done, so the figure stops being the thing still to reach */
.meter.is-done .meter-num b{color:var(--ink)}
.meter.is-over .meter-num b{color:var(--dim)}
.track{display:block;height:2px;border-radius:2px;background:var(--line-2);margin-top:9px;overflow:hidden}
.track i{display:block;height:100%;width:0;border-radius:2px;background:var(--gold);transition:width .9s var(--ease)}
.meter.is-over .track i{background:var(--dim)}
.meter-note{display:block;margin:8px 0 0;font-size:11px;color:var(--dim)}

/* Urgency.
 *
 * Four states, and only the rail uses these colours, so a red bar in the side
 * panel means one thing and cannot be confused with anything else in the panel.
 * Gold stays what it has always been, the figure you are working toward; the
 * two warning colours are borrowed from nothing else here.
 *
 * The flag is the word, not only the colour: a bar that is merely a different
 * shade of amber says nothing to anyone reading it in bright sunlight, and
 * nothing at all to a colour blind reader. */
.meter-flag{
  font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--dim);white-space:nowrap;
}
.meter.u-due .meter-flag{color:#C98A2E}
.meter.u-late .meter-flag{color:#C4553D}
.meter.u-done .meter-flag{color:var(--gold)}
.meter.u-due .track i{background:#C98A2E}
.meter.u-late .track i{background:#C4553D}
.meter.u-due .meter-num b{color:#C98A2E}
.meter.u-late .meter-num b{color:#C4553D}
/* the one that is late keeps a mark on the rail even while the pill is showing
   a different objective, so it cannot rotate quietly past you */
.meter.u-late{box-shadow:inset 2px 0 0 #C4553D}
.meter.u-due{box-shadow:inset 2px 0 0 #C98A2E}

/* one dot per live objective. Drawn only when there are several, since a single
   dot under a single objective is a decoration that says nothing. */
.meter-dots{display:flex;gap:4px;margin-top:9px}
.meter-dots i{
  display:block;width:14px;height:2px;border-radius:2px;
  background:var(--line-2);transition:background var(--fast) var(--ease);
}
.meter-dots i.on{background:var(--dim)}
.meter-dots i.u-due.on{background:#C98A2E}
.meter-dots i.u-late.on{background:#C4553D}
.meter-dots i.u-done.on{background:var(--gold)}

.who{display:flex;align-items:center;gap:4px;padding:2px}
/* the name is the way into your own account, so it is a button and reads as
   one on hover, the same weight of affordance the meter above it carries */
.who-face{
  flex:1;min-width:0;display:flex;align-items:center;gap:10px;padding:4px 6px 4px 4px;
  border:0;border-radius:var(--r-s);background:none;color:inherit;cursor:pointer;text-align:left;
  transition:background var(--fast) var(--ease);
}
.who-face:hover{background:var(--raised)}
.who-t{flex:1;min-width:0;display:grid;line-height:1.35}
.who-t b{font-size:12.5px;font-weight:550}
.who-t span{font-size:11px;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mono{
  display:grid;place-items:center;flex:none;width:28px;height:28px;border-radius:8px;
  background:var(--float);border:1px solid var(--line-2);color:var(--mute);
  font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
}
.mono.lg{width:42px;height:42px;border-radius:10px;font-size:15px}
.mono.gold{background:var(--gold-soft);border-color:var(--gold-line);color:var(--gold)}

/* the working column */
.work{display:flex;flex-direction:column;gap:var(--pad);min-width:0;min-height:0}

.head{
  flex:none;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--shadow-s);overflow:hidden;
}
/* the separators hang off the top of each row rather than the bottom, so
   whichever row happens to be last never draws a hairline against the edge */
.head>*+*{border-top:1px solid var(--line)}

.bar{
  flex:none;height:58px;display:flex;align-items:center;gap:14px;padding:0 16px;
}
.crumb{display:flex;align-items:center;gap:10px;min-width:0}
.crumb h1{margin:0;font-size:15px;font-weight:600;letter-spacing:-.01em;white-space:nowrap}
.tag{
  font-size:11px;font-weight:500;color:var(--dim);background:var(--raised);
  border:1px solid var(--line);border-radius:20px;padding:1px 8px;white-space:nowrap;
}
.bar-r{margin-left:auto;display:flex;align-items:center;gap:8px}

/* Searching everything. A 32px square beside the 440px field that filters one
   list: it was a 230px labelled box in the header, which at a glance was a
   second copy of the field. Same height, same border, so they read as one pair
   of controls of two obviously different kinds. */
.cmdb{
  flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:32px;height:32px;padding:0;border-radius:var(--r-s);
  border:1px solid var(--line);background:var(--raised);color:var(--dim);
  cursor:pointer;
  transition:border-color var(--fast) var(--ease),color var(--fast) var(--ease);
}
.cmdb:hover{border-color:var(--line-2);color:var(--ink)}
.cmdb:focus-visible{outline:none;border-color:var(--gold-line);color:var(--ink)}
.cmdb-ico{display:inline-flex;flex:none}
/* carried in the markup at every width and shown only where there is room for
   it, so the accessible name is the same control's whichever shape it is in */
.cmdb-t,.cmdb kbd{display:none}

/* The bar shape, worn in the header on the Overview. The class is on the button
   rather than on an ancestor because the button is moved between the two
   places rather than duplicated: one control, one listener, one name. */
.cmdb.wide{
  width:min(440px,100%);justify-content:flex-start;gap:8px;padding:0 8px 0 10px;
}
.cmdb.wide .cmdb-t{display:block;flex:1;text-align:left;font-size:12.5px}
.cmdb.wide kbd{display:inline-flex;flex:none}

/* The empty half of the header, which is where the Overview puts it. The
   section has no list to filter, so it has no sub-bar at all: saying it up here
   costs nothing, and the row it used to need was 51px of nothing. */
.bar-find{flex:1;display:flex;justify-content:center;min-width:0;padding:0 12px}
/* the header is tight once the title, the sync line and four controls are in
   it, so below this the bar goes back to being a square */
@media(max-width:920px){
  .bar-find{padding:0}
  .cmdb.wide{width:32px;justify-content:center;padding:0}
  .cmdb.wide .cmdb-t,.cmdb.wide kbd{display:none}
}

.seg{position:relative;display:flex;padding:3px;border-radius:var(--r-s);background:var(--raised);border:1px solid var(--line)}
.seg button{
  position:relative;z-index:1;border:0;background:none;cursor:pointer;
  padding:0 12px;height:26px;border-radius:5px;font-size:12px;color:var(--dim);
  transition:color var(--fast) var(--ease);
}
.seg button[aria-selected="true"]{color:var(--ink)}
/* A smaller one, for a card header. It marks the selection by filling the
   button rather than by sliding the thumb the toolbar version uses, because
   there is no thumb element here and one more thing to position on resize is
   not worth a three-way switch. */
.seg.sm{padding:2px}
.seg.sm button{height:22px;padding:0 9px;font-size:11px}
.seg.sm button[aria-selected="true"]{background:var(--float);color:var(--ink)}
.card-tools{display:flex;align-items:center;gap:8px}
/* the count sits beside the interval switch, so it takes that shape rather than
   the round tag used in the title bar: two different pills 8px apart read as a
   mistake */
.card-tools .tag{
  border-radius:var(--r-s);padding:0 9px;height:28px;display:inline-flex;align-items:center;
}
.seg-thumb{
  position:absolute;top:3px;bottom:3px;left:3px;width:0;border-radius:5px;
  background:var(--float);box-shadow:var(--shadow-s);
  transition:transform var(--mid) var(--spring),width var(--mid) var(--ease);
}
[data-theme="light"] .seg-thumb{background:#fff;border:1px solid var(--line)}

.primary{
  display:inline-flex;align-items:center;gap:7px;height:32px;padding:0 14px;
  border:0;border-radius:var(--r-s);background:var(--gold);color:#0B1220;
  font-size:12.5px;font-weight:600;cursor:pointer;white-space:nowrap;
  transition:filter var(--fast) var(--ease),transform var(--fast) var(--ease);
}
.primary:hover{filter:brightness(1.09)}
.primary:active{transform:scale(.97)}
.primary[disabled]{opacity:.4;cursor:default;filter:none;transform:none}
.ghost{
  display:inline-flex;align-items:center;gap:7px;height:32px;padding:0 12px;
  border:1px solid var(--line);border-radius:var(--r-s);background:var(--raised);
  color:var(--mute);font-size:12.5px;font-weight:500;cursor:pointer;white-space:nowrap;
  transition:color var(--fast) var(--ease),border-color var(--fast) var(--ease),background var(--fast) var(--ease);
}
.ghost:hover{color:var(--ink);border-color:var(--line-2)}
.ghost[disabled]{opacity:.4;cursor:default}
.ghost.danger:hover{color:var(--late);border-color:var(--late)}
.linkb{
  border:0;background:none;padding:0;cursor:pointer;color:var(--dim);
  font-size:12px;font-weight:500;transition:color var(--fast) var(--ease);
}
.linkb:hover{color:var(--gold)}

/* filter strip */
/* Three columns, not a flex row, so the filter is centred on the SCREEN rather
   than in whatever space the controls either side happen to leave. The two
   outer columns are given the same width for that reason: sized to their
   content, the wider left side would push the field off centre. */
/* The middle track is given a real width rather than `auto`. Sized to its
   content, `width:100%` on the field inside it resolves against a column that
   is itself sized by the field, which is circular: it collapsed to the width of
   the placeholder. The outer two are equal so the middle sits on the centre of
   the screen and not of the space the controls happen to leave. */
.subbar{
  flex:none;display:grid;align-items:center;gap:14px;padding:9px 16px;
  grid-template-columns:minmax(0,1fr) minmax(0,480px) minmax(0,1fr);
}
/* A row of chips shows every option all the time and spends the width on the
   ones you are not using. One control per question, carrying its own answer,
   is both quieter and shorter. */
/* One line, and the long value truncates rather than the row wrapping. The
   centred filter beside it is only centred while the two side columns are
   equal, so a second line here moves it off centre as well as making the bar
   taller — and it is the French that does it, `Tri Prochaine étape` being half
   again the width of `Sort Next step`. */
.tools{display:flex;gap:8px;flex-wrap:nowrap;min-width:0}
.tool{
  display:inline-flex;align-items:center;gap:8px;height:30px;padding:0 11px;min-width:0;
  border-radius:var(--r-s);border:1px solid var(--line);background:var(--raised);
  color:var(--mute);font-size:12.5px;cursor:pointer;white-space:nowrap;
  transition:border-color var(--fast) var(--ease),color var(--fast) var(--ease);
}
/* the label and the caret hold their size; the answer gives way first */
.tool>.tool-k,.tool>.tool-ico,.tool>.tool-caret{flex:none}
.tool>b{overflow:hidden;text-overflow:ellipsis;min-width:0}
/* Filter holds its width outright. Its answer is a filter name and always
   short, so letting it shrink in step with Sort truncated `Tout` to `T…` while
   `Prochaine étape` beside it still had room. One control gives way, and it is
   the one whose answer is long. */
.tools>.tool:first-child{flex:none}
.tool:hover{border-color:var(--line-2);color:var(--ink)}
.tool-k{color:var(--dim)}
.tool b{font-weight:550;color:var(--ink)}
.tool-ico,.tool-caret{display:inline-flex;color:var(--dim)}
.tool-caret{margin-left:-2px}
.tool[aria-expanded="true"]{border-color:var(--line-2);color:var(--ink);background:var(--float)}

/* Filtering the list you are on.
   Centred and wide, because at 150px tucked in beside Filter and Sort it was
   read as a second copy of the palette in the bar above. It is now the widest
   thing in its row and the only thing in the middle of the screen, which is
   the difference the eye catches before it reads either placeholder. */
/* the field and the everything-button travel together in the centre track */
.findgroup{display:flex;align-items:center;gap:8px;width:100%;min-width:0}
.find{
  display:flex;align-items:center;gap:8px;height:32px;padding:0 10px;
  flex:1;min-width:0;
  border-radius:var(--r-s);border:1px solid var(--line);background:var(--raised);
  transition:border-color var(--fast) var(--ease);
}
.find:focus-within{border-color:var(--gold-line)}
.find-ico{display:inline-flex;color:var(--dim);flex:none}
.find input{
  flex:1;min-width:0;height:100%;border:0;background:none;color:var(--ink);
  font-size:12.5px;
}
.find input:focus{outline:none}
.find input::placeholder{color:var(--dim)}
/* the browser's own clear button sits on top of ours and does not follow the
   theme, so it is removed and replaced */
.find input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
.find-x{
  display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:16px;height:16px;padding:0;border:0;border-radius:50%;
  background:var(--line-2);color:var(--base);cursor:pointer;
}
.find-x:hover{background:var(--mute)}
/* it holds a query, so it reads as active the way an applied filter does */
.find.on{border-color:var(--line-2)}
/* Below the width where three columns can hold a centred field, the row wraps
   and the filter takes the whole of the second line. Centring it in 200px of
   leftover space is not centring it. */
@media (max-width:900px){
  .subbar{grid-template-columns:1fr auto;row-gap:10px}
  .findgroup{grid-column:1/-1;grid-row:2;width:100%}
}
/* an active filter is the one thing in this row worth marking */
.tool.set{border-color:var(--gold-line);background:var(--gold-soft)}
.tool.set b,.tool.set .tool-ico{color:var(--gold)}
.tool.set.late{border-color:var(--late);background:var(--late-soft)}
.tool.set.late b,.tool.set.late .tool-ico{color:var(--late)}
/* `justify-self`, not `margin-left:auto`: in a three column grid the auto
   margin would push it against the centred field rather than to the far edge */
.subbar-r{justify-self:end;display:flex;align-items:center;gap:12px}

/* one popover, used by every menu in the panel */
.pop{
  position:fixed;z-index:35;min-width:212px;max-width:min(320px,92vw);
  padding:6px;border-radius:var(--r);background:var(--float);
  border:1px solid var(--line-2);box-shadow:var(--shadow);
  animation:popin .18s var(--ease) both;
}
@keyframes popin{from{opacity:0;transform:translateY(-5px) scale(.985)}to{opacity:1;transform:none}}
.pop-lab{padding:7px 9px 6px}
.pop-div{height:1px;background:var(--line);margin:5px 3px}
.pop-i{
  display:flex;align-items:center;gap:10px;width:100%;padding:7px 9px;border:0;
  border-radius:var(--r-s);background:none;color:var(--mute);cursor:pointer;text-align:left;
  transition:background var(--fast) var(--ease),color var(--fast) var(--ease);
}
.pop-i:hover,.pop-i[data-on="1"]{background:var(--raised);color:var(--ink)}
.pop-t{flex:1;min-width:0;display:grid;line-height:1.35}
.pop-t b{font-weight:450;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pop-t span{font-size:11px;color:var(--dim)}
.pop-n{font-size:11.5px;color:var(--dim);font-variant-numeric:tabular-nums}
.pop-tick{width:14px;display:inline-flex;color:var(--gold)}
.pop-i.on{color:var(--ink)}
.pop-i.on .pop-t b{font-weight:550}
.pop-i.late.on .pop-tick{color:var(--late)}
.shown{font-size:12px;color:var(--dim);white-space:nowrap;font-variant-numeric:tabular-nums}

/* quick add */
.composer{
  flex:none;display:grid;align-items:center;gap:10px;padding:12px 16px;
  grid-template-columns:minmax(0,1.1fr) minmax(0,1fr) minmax(0,1.8fr) 130px auto auto;
  background:var(--raised);animation:drop .3s var(--ease) both;
}
@keyframes drop{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
.cfield input,.composer select{
  width:100%;height:32px;padding:0 11px;border-radius:var(--r-s);
  border:1px solid var(--line);background:var(--panel);color:var(--ink);
  transition:border-color var(--fast) var(--ease);
}
.cfield input::placeholder{color:var(--dim)}
.cfield input:focus,.composer select:focus{outline:none;border-color:var(--gold-line)}
.composer select{padding:0 8px}

/* content */
/* a flex column, so the overview can be handed the exact height that is left
   rather than a percentage. A percentage min-height against a scroll container
   is not a definite length here, and it resolved to the overview's own content
   height, which is how the grid came out 83px taller than the screen. */
/* no padding of its own: the gap around the working column is the shell's, and
   everything inside is already a card */
.content{
  flex:1;min-height:0;overflow:auto;position:relative;
  display:flex;flex-direction:column;
}
.content>.view,.content>.blank{flex:none}
.view{animation:viewin .34s var(--ease) both}
@keyframes viewin{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

.blank{display:grid;justify-items:center;gap:10px;padding:min(14vh,110px) 20px;text-align:center}
.blank-mark{
  width:34px;height:34px;border-radius:10px;border:1px dashed var(--line-2);
  display:block;margin-bottom:6px;
}
.blank p{margin:0;font-size:14px}
.blank-sub{color:var(--dim);font-size:12.5px;max-width:44ch}

/* the table */
/* clip, not hidden. `overflow:hidden` makes the card its own scrollport, and a
   sticky head inside a box that cannot scroll never moves, so the column names
   scroll away with the rows. `clip` rounds the corners without doing that. */
.tablecard{
  border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
  overflow:clip;box-shadow:var(--shadow-s);
}
table{width:100%;border-collapse:separate;border-spacing:0}
thead th{
  position:sticky;top:0;z-index:2;background:var(--panel);
  border-bottom:1px solid var(--line);text-align:left;font-weight:500;
  font-size:11px;letter-spacing:.06em;color:var(--dim);
  padding:0 14px;height:38px;white-space:nowrap;user-select:none;
}
thead th.sortable{cursor:pointer;transition:color var(--fast) var(--ease)}
thead th.sortable:hover{color:var(--ink)}
th .caret{display:inline-block;margin-left:5px;opacity:0;transform:translateY(1px);transition:opacity var(--fast) var(--ease)}
th[aria-sort] .caret{opacity:1;color:var(--gold)}
th[aria-sort="ascending"] .caret{transform:rotate(180deg) translateY(1px)}
th.right,td.right{text-align:right}

tbody tr{
  cursor:pointer;
  animation:rowin .3s var(--ease) both;animation-delay:calc(var(--i,0)*14ms);
}
@keyframes rowin{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
tbody td{
  border-bottom:1px solid var(--line);padding:0 14px;height:52px;
  vertical-align:middle;transition:background var(--fast) var(--ease);
}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover td{background:var(--raised)}
tbody tr[aria-selected="true"] td{background:var(--float)}
tbody tr[aria-selected="true"] td:first-child{box-shadow:inset 2px 0 0 var(--gold)}
td.tight{width:1%;white-space:nowrap}

.cell{display:flex;align-items:center;gap:11px;min-width:0}
.cell-t{min-width:0;display:grid;line-height:1.35}
.cell-t b{font-weight:550;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cell-t span{font-size:11.5px;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* the same two lines, but in a column sized to its content, so nothing clips */
.stack{display:grid;line-height:1.35;white-space:nowrap}
.stack b{font-weight:450;font-size:12.5px}
.stack span{font-size:11px;color:var(--dim)}
.clamp{
  color:var(--mute);font-size:12.5px;display:-webkit-box;-webkit-line-clamp:2;
  -webkit-box-orient:vertical;overflow:hidden;max-width:52ch;
}
.muted{color:var(--dim)}
.late{color:var(--late)}
.num{font-variant-numeric:tabular-nums;white-space:nowrap}

.pill{
  display:inline-flex;align-items:center;gap:6px;height:23px;padding:0 9px;
  border-radius:20px;border:1px solid var(--line);background:var(--raised);
  font-size:11.5px;color:var(--mute);white-space:nowrap;
}
.pill i{width:5px;height:5px;border-radius:50%;background:var(--dim);flex:none}
.pill.s-1 i{background:var(--mute)}
.pill.s-2 i{background:var(--ink)}
.pill.gold{background:var(--gold-soft);border-color:var(--gold-line);color:var(--gold)}
.pill.gold i{background:var(--gold)}
.pill.late{background:var(--late-soft);border-color:var(--late);color:var(--late)}
.pill.late i{background:var(--late);animation:pulse 2.4s var(--ease) infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
.pill.off{opacity:.55}

.rowacts{display:flex;justify-content:flex-end;gap:2px;opacity:0;transform:translateX(4px);
  transition:opacity var(--fast) var(--ease),transform var(--fast) var(--ease)}
tbody tr:hover .rowacts,tbody tr:focus-within .rowacts{opacity:1;transform:none}
.rowacts .iconb{width:26px;height:26px}

.skel td{height:52px}
.sk{height:9px;border-radius:5px;background:var(--line);position:relative;overflow:hidden}
.sk::after{
  content:"";position:absolute;inset:0;transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,var(--line-2),transparent);
  animation:sweep 1.35s infinite;
}
@keyframes sweep{to{transform:translateX(100%)}}

/* the timeline.
   The second view of a section is not a second table. It answers the only
   question a pipeline actually raises, which is what is late and what is next,
   so the rows hang off a dated rail instead of sitting in a grid. */
.line{display:grid;gap:2px;max-width:1180px}
.lgroup{display:grid;grid-template-columns:150px minmax(0,1fr);gap:0}
.lmark{
  position:relative;padding:16px 22px 16px 0;text-align:right;
  border-right:1px solid var(--line);
}
.lmark .lab{margin-bottom:4px}
.lmark .n{font-size:11.5px;color:var(--dim);font-variant-numeric:tabular-nums}
/* centred on the rail rather than measured from it: the marker's own right edge
   sits on the line, then it is pushed back by half its width plus half the
   line's, so the sizes can change without the arithmetic going stale. Vertically
   it lands on the middle of the group's first line of type. */
.lmark::after{
  content:"";position:absolute;right:0;top:23px;width:9px;height:9px;border-radius:50%;
  background:var(--line-2);border:2px solid var(--base);
  transform:translate(calc(50% + .5px),-50%);
}
.lgroup.is-late .lmark::after{background:var(--late)}
.lgroup.is-now .lmark::after{background:var(--gold)}
.lgroup.is-late .lmark .lab{color:var(--late)}
.lgroup.is-now .lmark .lab{color:var(--gold)}
.lrows{padding:9px 0 9px 22px;display:grid;gap:8px;min-width:0}
.lrow{
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:14px;align-items:center;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  padding:11px 14px;cursor:pointer;text-align:left;width:100%;
  animation:rowin .3s var(--ease) both;animation-delay:calc(var(--i,0)*16ms);
  transition:border-color var(--fast) var(--ease),transform var(--fast) var(--ease),box-shadow var(--fast) var(--ease);
}
.lrow:hover{border-color:var(--line-2);transform:translateX(2px);box-shadow:var(--shadow-s)}
.lrow .clamp{-webkit-line-clamp:1;font-size:12px}
.lright{display:flex;align-items:center;gap:12px;white-space:nowrap}
.ltime{font-size:12px;color:var(--dim);font-variant-numeric:tabular-nums}

/* overview.
   No measure cap and no dead band at the foot: the overview is the whole
   working column, and the last row of cards takes whatever height is left. */
.dash{display:flex;flex-direction:column}
.dash-head{justify-content:center;padding:18px 20px}
.dash-head h2{margin:7px 0 5px;font-family:var(--serif);font-weight:400;font-size:clamp(24px,2.4vw,34px);line-height:1.05}
.dash-sub{margin:0;color:var(--mute);max-width:60ch}

.grid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:12px}

/* Filling the screen only makes sense while the twelve column layout is whole.
   Once the cards stack there are eight of them and no viewport to fit them in,
   so below this width the overview goes back to its own height and scrolls.
   Applied everywhere, this crushed every card on a phone to a clipped strip. */
@media(min-width:1241px){
  #v-dash{flex:1 1 auto;min-height:0}
  .grid{
    flex:1;min-height:0;
    grid-template-rows:auto auto minmax(140px,1.15fr) minmax(130px,1fr);
  }
  /* the two lower rows take exactly what is left, and a list that cannot fit
     scrolls inside its own card rather than pushing the page taller than the
     screen and leaving a strip of nothing under the last row */
  .card{min-height:0}
  .feed{overflow:auto}
  /* the chart gives up its floor here, so the row can shrink to what is left */
  .chart{min-height:110px}
}
.span3{grid-column:span 3}.span4{grid-column:span 4}.span6{grid-column:span 6}
.span8{grid-column:span 8}.span12{grid-column:span 12}
.card{
  display:flex;flex-direction:column;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  padding:16px;min-width:0;box-shadow:var(--shadow-s);
  animation:rowin .38s var(--ease) both;animation-delay:calc(var(--i,0)*35ms);
  transition:border-color var(--fast) var(--ease);
}
.card:hover{border-color:var(--line-2)}
.card-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px}
.kpi-body{display:flex;align-items:center;justify-content:space-between;gap:14px;margin:12px 0 10px}
.fig{margin:0;display:flex;align-items:baseline;gap:8px}
.fig b{font-family:var(--serif);font-weight:400;font-size:40px;line-height:1;font-variant-numeric:tabular-nums}
.fig span{font-size:12px;color:var(--dim)}
.foot{margin:0;font-size:11.5px;color:var(--dim)}
.foot.late{color:var(--late)}
.ring{width:46px;height:46px;flex:none}
.ring circle{fill:none;stroke-width:3;stroke-linecap:round}
.ring .bg{stroke:var(--line-2)}
.ring .fg{stroke:var(--gold);transition:stroke-dashoffset 1s var(--ease)}
.spark{width:90px;height:34px;flex:none}
.spark svg{width:100%;height:100%;overflow:visible}

.chart{position:relative;flex:1;display:flex;flex-direction:column;min-height:190px}
.chart svg{display:block;width:100%;flex:1;min-height:0;overflow:visible}
.chart-scale{display:flex;justify-content:space-between;margin-top:9px;font-size:10.5px;color:var(--dim)}
.chart-scale .dim{opacity:0}
.chart-tip{
  position:absolute;top:-4px;transform:translateX(-50%);white-space:nowrap;pointer-events:none;
  background:var(--float);border:1px solid var(--line-2);color:var(--ink);
  font-size:11.5px;padding:6px 9px;border-radius:6px;box-shadow:var(--shadow);
}

.funnel{flex:1;display:grid;gap:12px;align-content:space-between}
.fn{display:grid;grid-template-columns:88px 1fr 26px;gap:11px;align-items:center}
.fn-name{font-size:11.5px;color:var(--dim);white-space:nowrap}
.fn-track{height:6px;border-radius:6px;background:var(--line);overflow:hidden}
.fn-track i{display:block;height:100%;width:0;border-radius:6px;background:var(--mute);transition:width .8s var(--ease)}
.fn.is-target .fn-track i{background:var(--gold)}
.fn b{font-weight:500;font-size:12px;text-align:right;color:var(--mute);font-variant-numeric:tabular-nums}

.feed{list-style:none;margin:0;padding:0;flex:1;display:grid;align-content:start}
.feed li{
  display:flex;align-items:center;gap:11px;padding:10px 8px;border-radius:var(--r-s);
  cursor:pointer;transition:background var(--fast) var(--ease);
}
.feed li:hover{background:var(--raised)}
.feed li .cell-t{flex:1}
.feed .when{font-size:11.5px;color:var(--dim);white-space:nowrap;font-variant-numeric:tabular-nums}
.feed li.is-late .when{color:var(--late)}
.feed-none{color:var(--dim);cursor:default;font-size:12.5px;padding:10px 8px}
.feed-none:hover{background:none}

/* the record panel */
.scrim{
  position:fixed;inset:0;z-index:20;background:rgba(4,8,16,.55);
  backdrop-filter:blur(2px);animation:fade .25s var(--ease) both;
}
[data-theme="light"] .scrim{background:rgba(11,18,32,.28)}
@keyframes fade{from{opacity:0}to{opacity:1}}

.rp{
  position:fixed;top:0;right:0;bottom:0;width:min(660px,100vw);z-index:21;
  background:var(--panel);border-left:1px solid var(--line-2);
  display:flex;flex-direction:column;box-shadow:var(--shadow);
  animation:panelin .4s var(--ease) both;
}
@keyframes panelin{from{transform:translateX(28px);opacity:0}to{transform:none;opacity:1}}
.rp-head{display:flex;align-items:flex-start;gap:13px;padding:18px 18px 14px}
.rp-title{flex:1;min-width:0}
.rp-meta{display:flex;align-items:center;gap:9px;margin-bottom:5px}
.ref{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--gold)}
.rp-title h2{margin:0;font-family:var(--serif);font-weight:400;font-size:24px;line-height:1.15}
.rp-sub{margin:5px 0 0;font-size:12px;color:var(--dim)}

/* the stage rail. Where the record stands, read left to right, at the top of
   the panel. It is display until you press Edit, and only then does a stage
   become a thing you can press. */
/* No band behind it and no rule above or below it. Boxed, it read as a strip
   bolted between the title and the record instead of part of either. It sits on
   the panel's own left edge, the same 18px as the title, the tabs and every
   card in the body. */
.stages{display:flex;gap:4px;padding:4px 18px 16px;flex:none}
.stg{
  position:relative;flex:1;min-width:0;border:0;background:none;padding:0;text-align:left;
  color:var(--dim);font-size:11px;letter-spacing:.04em;cursor:default;
  display:grid;gap:7px;
}
.stg::before{
  content:"";display:block;height:3px;border-radius:3px;background:var(--line-2);
  transition:background var(--mid) var(--ease);
}
.stg span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stg.done::before{background:var(--mute)}
.stg.done{color:var(--mute)}
.stg.on::before{background:var(--gold)}
.stg.on{color:var(--gold);font-weight:550}
.stg.off::before{background:var(--late)}
.stg.off{color:var(--late)}
.stages.editing .stg{cursor:pointer}
.stages.editing .stg:hover::before{background:var(--ink)}
.stages.editing .stg.on:hover::before{background:var(--gold)}

/* The end of the run. One segment with one bar like every other, so the rail
   keeps its rhythm; it holds the outcome once there is one and the question
   until then. Dashed while unanswered: the step exists, nothing has been said
   about it, and that is different from a step still ahead of you. */
.stg.stg-fin::before{
  background:repeating-linear-gradient(90deg,
    var(--line-2) 0 6px, transparent 6px 11px);
}
.stages.editing .stg.stg-fin{cursor:pointer}
.stages.editing .stg.stg-fin:hover::before{
  background:repeating-linear-gradient(90deg,
    var(--ink) 0 6px, transparent 6px 11px);
}

.tabs{display:flex;gap:20px;padding:0 18px;border-bottom:1px solid var(--line);flex:none}
.tab{
  position:relative;border:0;background:none;cursor:pointer;padding:0 0 10px;
  font-size:12.5px;color:var(--dim);transition:color var(--fast) var(--ease);
}
.tab:hover{color:var(--ink)}
.tab[aria-selected="true"]{color:var(--ink)}
.tab::after{
  content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;border-radius:2px;
  background:var(--gold);transform:scaleX(0);transition:transform var(--mid) var(--spring);
}
.tab[aria-selected="true"]::after{transform:scaleX(1)}

.rp-scroll{flex:1;min-height:0;overflow:auto;padding:18px}
.pane{display:grid;gap:16px;animation:viewin .3s var(--ease) both}

.facts{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
}
.fact{background:var(--panel);padding:11px 13px;min-width:0}
/* an odd count leaves a hole in the second column, which reads as a missing
   field rather than as the end of the list */
.fact:last-child:nth-child(odd){grid-column:span 2}
.fact dt{margin:0 0 3px;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--dim)}
.fact dd{margin:0;font-size:12.5px;overflow-wrap:anywhere}
.mail{color:var(--gold);text-decoration:none;border-bottom:1px solid transparent}
.mail:hover{border-bottom-color:var(--gold)}

.block{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);overflow:hidden}
.block-h{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:11px 14px;border-bottom:1px solid var(--line);background:var(--raised);
}
.block-b{padding:14px;display:grid;gap:13px}
.fld{display:grid;grid-template-columns:112px minmax(0,1fr);gap:12px;align-items:start}
.fld>.lab{padding-top:8px}
.fld input,.fld textarea,.fld select{
  width:100%;padding:8px 11px;border-radius:var(--r-s);border:1px solid var(--line);
  background:var(--raised);color:var(--ink);resize:vertical;
  transition:border-color var(--fast) var(--ease),background var(--fast) var(--ease);
}
/* read mode. The same grid, the value set as text, so pressing Edit changes
   what a field is rather than where it sits. */
.val{margin:0;font-size:13px;padding-top:7px;overflow-wrap:anywhere;white-space:pre-wrap}
.val.empty{color:var(--dim)}
.fld input::placeholder,.fld textarea::placeholder{color:var(--dim)}
.fld input:focus,.fld textarea:focus,.fld select:focus{outline:none;border-color:var(--gold-line);background:var(--panel)}
.fld select option{background:var(--panel)}

/* A dialling code and a number, reading as one field.
   The code track is `auto` so it takes the width of its own longest option
   rather than a share of the row: the number is the part you are typing and it
   should keep the space. */
.tel{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;align-items:center}
.tel .tel-code{width:auto;font-variant-numeric:tabular-nums}

.qsec{border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.qsec-h{
  display:flex;align-items:center;gap:11px;padding:11px 14px;background:var(--raised);
  border-bottom:1px solid var(--line);cursor:pointer;user-select:none;
}
.qsec-h b{font-weight:550;font-size:13px}
.qsec-h .n{
  width:20px;height:20px;border-radius:6px;display:grid;place-items:center;flex:none;
  background:var(--float);color:var(--dim);font-size:10.5px;
}
.qsec-h .chev{margin-left:auto;color:var(--dim);transition:transform var(--mid) var(--ease)}
.qsec[data-open="false"] .chev{transform:rotate(-90deg)}
.qsec[data-open="false"] .qsec-b{display:none}
.qsec-b{padding:4px 14px 12px}
.qrow{display:grid;grid-template-columns:minmax(0,190px) minmax(0,1fr);gap:14px;padding:9px 0;border-bottom:1px solid var(--line)}
.qrow:last-child{border-bottom:0}
.qrow dt{margin:0;font-size:11.5px;color:var(--dim)}
.qrow dd{margin:0;font-size:12.5px;overflow-wrap:anywhere}
.qrow dd.none{color:var(--late)}
.quote{margin:12px 0 0;padding:11px 13px;border-radius:var(--r-s);background:var(--raised);border-left:2px solid var(--gold)}
.quote p{margin:0 0 5px;font-size:11.5px;color:var(--dim)}
.quote blockquote{margin:0;font-family:var(--serif);font-size:16px;line-height:1.5}

/* The six lenses.
 *
 * Same block as the transcript above, because it is the same kind of pane. The
 * only thing that differs is the answering: a question is a sentence, not a
 * field label, so it sits above its box rather than in a label column. At the
 * .qrow column width a full question wraps to four lines beside a one-line
 * answer, which reads as the answer being an afterthought. */
.lens{display:grid;gap:5px;padding:9px 0;border-bottom:1px solid var(--line)}
.lens:last-child{border-bottom:0}
.lens-q{font-size:12px;color:var(--mute);line-height:1.45}
.lens textarea{
  width:100%;padding:7px 10px;border-radius:var(--r-s);border:1px solid var(--line);
  background:var(--raised);color:var(--ink);resize:vertical;font-size:12.5px;
  transition:border-color var(--fast) var(--ease),background var(--fast) var(--ease);
}
.lens textarea:focus{outline:none;border-color:var(--gold-line);background:var(--panel)}
/* The instruction on a lens that has one. Not a question, so it is set as the
   aside it is rather than as the first row of the list.
   Not gold: two lenses carry one of these and only one of them is about the
   constraint, and gold on `Become a customer.` says the wrong thing. */
.lens-note{margin:9px 0 2px;font-size:11.5px;color:var(--mute)}
.pane-lead{margin:0;font-size:12.5px;color:var(--mute)}
.pane-none{margin:0;padding:22px 0;text-align:center;font-size:12.5px;color:var(--dim)}
/* the Cold stage's row, where the scan stands in for the note: how far it got,
   and the way into it */
.scan-cta{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap}
.scan-cta .val{padding-top:7px;font-variant-numeric:tabular-nums}

.rp-foot{
  flex:none;display:flex;align-items:center;gap:9px;padding:12px 18px;
  border-top:1px solid var(--line);background:var(--panel);
}
.state{margin-right:auto;font-size:11.5px;color:var(--dim);display:flex;align-items:center;gap:7px}
.state::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--line-2)}
.rp-foot.is-dirty .state{color:var(--gold)}
.rp-foot.is-dirty .state::before{background:var(--gold)}
/* Save refused because one field still has to be answered. Not gold: gold is
   the colour of the thing you are working toward, and this is the other one. */
.rp-foot.is-blocked .state{color:var(--late)}
.rp-foot.is-blocked .state::before{background:var(--late)}
/* and the field itself, at the other end of a panel that scrolls. The rule
   alone, not a fill: it is a field waiting for an answer, not an error in what
   is already typed. */
.block-b .fld input.wants{
  border-color:var(--late);
  box-shadow:inset 0 -1px 0 var(--late);
}

.confirm{
  position:absolute;inset:auto 0 0 0;z-index:2;padding:16px 18px;
  background:var(--float);border-top:1px solid var(--gold-line);
  display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;
  animation:drop .26s var(--ease) both;
}
.confirm p{margin:0;font-size:13px}
.confirm div{display:flex;gap:8px;flex-wrap:wrap}
/* the delete confirmation reads as the one that cannot be undone, and its own
   border says so before the words do */
#rp-delc{border-top-color:#C4553D}

/* What was written at the stages this record has already been through.
   A list of facts, not a stack of cards: each is a stage name, when it
   happened, and what was said, on a hairline. The record panel is narrow and
   four of these boxed would read as four more forms. */
.past{padding:11px 0;border-top:1px solid var(--line)}
.past:first-child{padding-top:2px;border-top:0}
.past-h{
  display:flex;align-items:baseline;gap:9px;margin:0 0 5px;
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
}
.past-h b{font-weight:550;color:var(--mute)}
.past-h span{letter-spacing:0;text-transform:none;font-size:11.5px;color:var(--dim)}
p.past-note{margin:0;font-size:12.5px;line-height:1.55;color:var(--ink);white-space:pre-wrap}
p.past-note:empty::before{content:"—";color:var(--dim)}
/* editable in edit mode, on the same hairline rather than in a filled box, so
   the block does not change shape when Edit is pressed */
textarea.past-note{
  width:100%;padding:0;border:0;background:none;color:var(--ink);
  font:inherit;font-size:12.5px;line-height:1.55;resize:vertical;
}
textarea.past-note:focus{outline:none}

/* The only destructive control in the panel. Not gold: gold is the colour of
   the thing you are working toward, and this is not that. */
.danger{
  border:1px solid rgba(196,85,61,.5);background:rgba(196,85,61,.12);color:#C4553D;
  border-radius:var(--r-s);padding:8px 14px;font:inherit;font-size:13px;cursor:pointer;
  transition:background var(--fast) var(--ease);
}
.danger:hover{background:rgba(196,85,61,.2)}
.iconb.danger{padding:0;background:none;border:0;color:var(--dim)}
.iconb.danger:hover{color:#C4553D;background:rgba(196,85,61,.12)}
/* Armed, waiting for the second press. It holds the hover appearance rather
   than inventing a third one, and outlines itself so the state survives a
   pointer that has moved off it. The title carries the question in words: an
   outline alone says nothing to a screen reader and nothing in sunlight. */
.iconb.danger.armed{color:#C4553D;background:rgba(196,85,61,.16);
  box-shadow:inset 0 0 0 1px rgba(196,85,61,.55)}

/* command palette */
.cmd{position:fixed;inset:0;z-index:30;background:rgba(4,8,16,.55);backdrop-filter:blur(3px);
  display:grid;place-items:start center;padding:12vh 16px 16px;animation:fade .2s var(--ease) both}
[data-theme="light"] .cmd{background:rgba(11,18,32,.3)}
.cmd-box{
  width:min(620px,100%);background:var(--panel);border:1px solid var(--line-2);
  border-radius:14px;box-shadow:var(--shadow);overflow:hidden;
  animation:cmdin .28s var(--spring) both;
}
@keyframes cmdin{from{opacity:0;transform:translateY(-10px) scale(.985)}to{opacity:1;transform:none}}
.cmd-top{display:flex;align-items:center;gap:11px;padding:14px 16px;border-bottom:1px solid var(--line)}
.cmd-top input{flex:1;min-width:0;border:0;background:none;font-size:15px;outline:none}
.cmd-top input::placeholder{color:var(--dim)}
.cmd-list{max-height:min(52vh,420px);overflow:auto;padding:8px}
.cmd-group{padding:10px 10px 5px}
.cmd-i{
  display:flex;align-items:center;gap:11px;width:100%;padding:9px 10px;border:0;
  border-radius:var(--r-s);background:none;color:var(--mute);cursor:pointer;text-align:left;
}
.cmd-i .cell-t{flex:1}
.cmd-i[data-on="1"]{background:var(--raised);color:var(--ink)}
.cmd-i[data-on="1"] .hintk{opacity:1}
.hintk{opacity:0;font-size:10.5px;color:var(--dim);transition:opacity var(--fast) var(--ease)}
.cmd-foot{display:flex;gap:16px;padding:10px 16px;border-top:1px solid var(--line);font-size:11px}
.cmd-none{padding:26px 12px;text-align:center;color:var(--dim);font-size:13px}

/* the one dialog. A popover is the wrong shape for a form you have to fill in
   and get right, so this is a proper sheet with its own save. */
.sheet{
  position:fixed;inset:0;z-index:32;background:rgba(4,8,16,.55);backdrop-filter:blur(3px);
  display:grid;place-items:center;padding:20px;animation:fade .2s var(--ease) both;
}
[data-theme="light"] .sheet{background:rgba(11,18,32,.3)}
.sheet-box{
  width:min(420px,100%);background:var(--panel);border:1px solid var(--line-2);
  border-radius:14px;box-shadow:var(--shadow);overflow:hidden;
  animation:cmdin .28s var(--spring) both;
}
.sheet-head{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:15px 16px;border-bottom:1px solid var(--line);
}
.sheet-head h2{margin:0;font-family:var(--serif);font-weight:400;font-size:19px}
.sheet-body{padding:16px;display:grid;gap:13px}
.sheet-body .fld{grid-template-columns:106px minmax(0,1fr);align-items:center}
.sheet-body .fld>.lab{padding-top:0}
.sheet-preview{
  margin:3px 0 0;padding:11px 12px;border-radius:var(--r-s);background:var(--raised);
  border:1px solid var(--line);font-size:12.5px;color:var(--mute);
}
.sheet-preview{display:grid;gap:4px}
.sheet-preview b{color:var(--gold);font-weight:550}
.preview-note{color:var(--dim);font-size:11.5px}
.sheet-note{margin:0;min-height:1.2em;font-size:12px;color:var(--late)}
.sheet-lead{margin:0;font-size:12.5px;color:var(--mute)}
/* a button in a grid of fields stretches to the column and then reads as one */
.sheet-body>.ghost{justify-self:start}
.sheet-acts{display:flex;flex-wrap:wrap;gap:8px}

/* A sheet is a ledger, not a stack of boxes.
 *
 * Redone 2026-08-05. Filled, bordered inputs on a raised panel inside a dark
 * dialog are three greys arguing with each other, and the read-only rows then
 * look like disabled fields rather than facts. Every control here is now a
 * value on a hairline, which is the language the record panel and the site's
 * own forms already use, so the label column reads straight down and the only
 * thing that changes between a fact and a field is whether it has a rule under
 * it. Scoped to .sheet-body: the composer and the record panel keep filled
 * controls, which suit a dense table view. */
.sheet-body .fld input,
.sheet-body .fld textarea,
.sheet-body .fld select{
  padding:6px 0;border:0;border-bottom:1px solid var(--line);border-radius:0;
  background:none;
  transition:border-color var(--fast) var(--ease);
}
.sheet-body .fld input:focus,
.sheet-body .fld textarea:focus,
.sheet-body .fld select:focus{
  outline:none;border-bottom-color:var(--gold);background:none;
}
.sheet-body .fld select{padding-right:2px}

/* a field whose label sits above it rather than beside it, for the places where
   the column is too narrow for a ledger */
.sheet-body .fld.stack{grid-template-columns:1fr;gap:5px;align-items:start}
.sheet-body .fld.stack>.lab{padding-top:0}

/* The account.
 *
 * Every other sheet is one form you fill and dismiss. This is the account
 * behind the whole panel, and at 420px it looked like another of them. It is
 * wider, it opens with who you are instead of with a field, and it splits in
 * two: what you are on the left, how you get in on the right. The width is the
 * signal that this is somewhere else, and the split is what earns the width
 * rather than just stretching a form across it. */
.acct-box{width:min(660px,100%)}
.acct-head{align-items:center;gap:14px}
.acct-who{flex:1;min-width:0}
.acct-who h2{margin:0}
.acct-sub{
  margin:3px 0 0;font-size:10.5px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--gold);
}
/* the right column is three fields and a button against the left's two, so it
   takes the extra width rather than the two splitting it evenly and leaving a
   hole on the left */
.acct-grid{grid-template-columns:minmax(0,.86fr) minmax(0,1.14fr);gap:0 26px;align-items:start}
.acct-col{display:grid;gap:13px;align-content:start}
/* the right column carries the rule, so the two read as two things without a
   box around either */
.acct-grid .acct-col:nth-child(2){padding-left:26px;border-left:1px solid var(--line)}
.acct-h{margin:0 0 1px}
.acct-grid .sheet-note{grid-column:1/-1}
/* anything that belongs to neither column and runs under both */
.acct-grid .span2{grid-column:1/-1}
@media (max-width:640px){
  .acct-grid{grid-template-columns:1fr;gap:18px}
  .acct-grid .acct-col:nth-child(2){
    padding-left:0;padding-top:18px;border-left:0;border-top:1px solid var(--line);
  }
}

/* The client sheet.
   Four fields each side, so an even split rather than the account sheet's
   weighting, and the rule is drawn on the second column by adjacency rather
   than by position: a lead paragraph sits above both, which makes the left
   column the second child of the body and would put the rule on the wrong
   side of the sheet. */
/* Capped and scrolled the same way the invoice body is. Stacked on a phone the
   sheet is 940px tall, which put Add the client below the bottom of the screen
   with nothing able to scroll to it. Vertical only: sideways overflow would be
   a bug in a column width, not something to scroll to. */
.cli-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  max-height:min(74vh,760px);overflow-y:auto;overflow-x:hidden}
.cli-grid .acct-col:nth-child(2){padding-left:0;border-left:0}
.cli-grid .acct-col + .acct-col{padding-left:26px;border-left:1px solid var(--line)}
/* the lead introduces both columns, so it needs air under it or it reads as a
   caption on the left one */
.cli-grid .sheet-lead{margin:0 0 14px}
/* and the constraint needs to clear the foot of the dividing rule, or it looks
   like it is hanging off the left column */
.cli-grid .fld.span2{margin-top:8px}
@media (max-width:640px){
  /* the columns are restated here, not only reset: `.cli-grid` is declared
     after the shared mobile block, so the two-column rule outranks it and the
     sheet kept both columns at 164px on a phone */
  .cli-grid{grid-template-columns:1fr;gap:18px}
  /* and the account sheet's mobile rule is undone before it is redrawn. It
     targets `nth-child(2)`, which is the SECOND column there and the FIRST one
     here, because a lead paragraph sits above both: stacked, it drew a rule
     across the top of the sheet with nothing above it. */
  .cli-grid .acct-col:nth-child(2){padding-top:0;border-top:0}
  .cli-grid .acct-col + .acct-col{
    padding-left:0;padding-top:18px;border-left:0;border-top:1px solid var(--line);
  }
}
.sheet-body .val{padding-top:0;font-size:12.5px;color:var(--mute)}
.sheet-foot{
  display:flex;justify-content:flex-end;gap:8px;padding:13px 16px;
  border-top:1px solid var(--line);background:var(--raised);
}
.sheet-foot .danger{margin-right:auto}

/* The invitation. It is readable exactly once, because only its hash is stored,
   so it is set as something you copy rather than something you read. */
.invite{display:grid;gap:7px;padding:12px;border-radius:var(--r-s);
  background:var(--gold-soft);border:1px solid var(--gold-line)}
.invite-row{display:flex;gap:8px}
.invite-row input{
  flex:1;min-width:0;height:32px;padding:0 10px;border-radius:var(--r-s);
  border:1px solid var(--line);background:var(--panel);color:var(--ink);
  font-size:12px;font-variant-numeric:tabular-nums;
}
.invite-row input:focus{outline:none;border-color:var(--gold-line)}
.invite-note{margin:0;font-size:11px;color:var(--dim)}

/* The invoice editor.
 *
 * Wider than the account sheet: it is a document being assembled and the line
 * table needs the room. The lines are a grid rather than a table element, so
 * the header and every row share one column definition and cannot drift apart.
 */
.inv-box{width:min(880px,100%)}
/* vertical only. Anything that overflows sideways is a bug in a column
   width, not something to scroll to. */
.inv-body{max-height:min(74vh,760px);overflow-y:auto;overflow-x:hidden}
.inv-cols{display:grid;grid-template-columns:1fr 1fr;gap:0 26px;align-items:start}
.inv-cols .acct-col:nth-child(2){padding-left:26px;border-left:1px solid var(--line)}
.inv-lines{display:grid;gap:8px;padding-top:15px;margin-top:3px;border-top:1px solid var(--line)}
.inv-head,.inv-row{
  display:grid;grid-template-columns:minmax(0,1fr) 74px 116px 78px 96px 30px;
  gap:8px;align-items:center;
}
.inv-head .num{text-align:right}
.inv-row input,.inv-row select{
  width:100%;padding:6px 0;border:0;border-bottom:1px solid var(--line);border-radius:0;
  background:none;color:var(--ink);font:inherit;font-size:12.5px;
  transition:border-color var(--fast) var(--ease);
}
.inv-row input:focus,.inv-row select:focus{outline:none;border-bottom-color:var(--gold)}
/* the two figure columns are read down a column, not across a row, so they are
   tabular and right-aligned even while being typed into */
.inv-row input:nth-child(2),.inv-row input:nth-child(3){
  text-align:right;font-variant-numeric:tabular-nums;
}
.inv-desc{display:block;min-width:0}
.inv-desc select,.inv-desc input{width:100%}
.inv-amt{font-size:12.5px;font-variant-numeric:tabular-nums;text-align:right;color:var(--mute)}
.inv-lines .ghost{justify-self:start}
.inv-tot{
  display:grid;gap:6px;justify-items:end;padding-top:12px;margin-top:2px;
  border-top:1px solid var(--line);
}
.inv-tot div{display:flex;align-items:baseline;gap:14px;font-size:12.5px;color:var(--dim)}
.inv-tot b{min-width:120px;text-align:right;color:var(--ink);font-variant-numeric:tabular-nums}
.inv-tot .big{font-family:var(--serif);font-size:16px;color:var(--ink)}
.inv-tot .big b{font-size:16px;color:var(--gold)}
@media (max-width:760px){
  .inv-cols{grid-template-columns:1fr;gap:18px}
  .inv-cols .acct-col:nth-child(2){padding-left:0;border-left:0}
  /* the line collapses to two rows rather than scrolling sideways: a numeric
     field you cannot see while typing into it is worse than a tall form */
  .inv-head{display:none}
  .inv-row{grid-template-columns:1fr 1fr 30px;gap:6px 8px}
  .inv-row input:first-child{grid-column:1/-1}
}

/* toasts */
/* bottom left, not bottom right. The record panel's Save and Discard sit in the
   bottom right corner, and a toast that lands on the button you are about to
   press is worse than no toast at all. */
.toasts{position:fixed;left:18px;bottom:18px;z-index:40;display:grid;gap:8px;justify-items:start}
.toast{
  display:flex;align-items:center;gap:12px;padding:11px 13px;border-radius:var(--r);
  background:var(--float);border:1px solid var(--line-2);box-shadow:var(--shadow);
  font-size:12.5px;max-width:380px;animation:toastin .32s var(--spring) both;
}
.toast.out{animation:toastout .22s var(--ease) forwards}
@keyframes toastin{from{opacity:0;transform:translateY(10px) scale(.97)}to{opacity:1;transform:none}}
@keyframes toastout{to{opacity:0;transform:translateY(6px) scale(.98)}}
.toast i{width:6px;height:6px;border-radius:50%;background:var(--gold);flex:none}
.toast.bad i{background:var(--late)}
.toast .linkb{color:var(--gold)}
.toast .linkb:hover{text-decoration:underline}

/* one switch, so nothing added later can slip past it */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;animation-delay:0ms !important;
    transition-duration:.001ms !important;
  }
}

.only-narrow{display:none}
.only-wide{display:inline-flex}

@media(max-width:1240px){
  .span3{grid-column:span 6}
  .span8{grid-column:span 12}
  .span4{grid-column:span 12}
}
/* the palette trigger used to be a labelled box in the header that collapsed to
   an icon here; it is a 32px square beside the filter at every width now */
@media(max-width:920px){
  .only-narrow{display:inline-flex}
  .only-wide{display:none}
  .lgroup{grid-template-columns:1fr}
  .lmark{text-align:left;padding:14px 0 4px;border-right:0}
  .lmark::after{right:auto;left:-14px;top:21px;transform:translateY(-50%)}
  .lrows{padding:0 0 10px}
  .stages{overflow-x:auto}
  .stg{min-width:74px}
  .side{
    position:fixed;top:var(--pad);bottom:var(--pad);left:var(--pad);width:264px;z-index:25;
    transform:translateX(calc(-100% - var(--pad)));
    transition:transform var(--mid) var(--ease);
  }
  body.side-open .side{transform:none;box-shadow:var(--shadow)}
  html.side-closed{--side:0px}
  .app{grid-template-columns:minmax(0,1fr)}
  .span3,.span6,.span4,.span8{grid-column:span 12}
  .composer{grid-template-columns:1fr}
  .app{padding:8px;gap:8px}
  .bar{padding:0 12px;gap:8px}
  .subbar{padding:9px 12px}
  .fld{grid-template-columns:1fr;gap:5px}
  .fld>.lab{padding-top:0}
  .facts{grid-template-columns:1fr}
  .qrow{grid-template-columns:1fr;gap:3px}
  .rp{width:100vw}
  .sync{display:none}
}

/* the sync time sits in the bar beside Refresh. A whole strip along the foot of
   the screen for four shortcut hints and a clock was a strip of chrome. */
.sync{font-size:11px;color:var(--dim);font-variant-numeric:tabular-nums;white-space:nowrap}

/* sign in, the gate the console sits behind */
body.signin{display:block;background:var(--panel);overflow:auto}
.gate{min-height:100svh;display:grid;grid-template-columns:1fr 1fr}
.gate-plate{background:url("/lib/gate.webp") center/cover no-repeat;position:relative}
.gate-plate::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(to right,rgba(11,18,32,0) 70%,rgba(11,18,32,.4) 100%);
}
.gate-panel{
  background:var(--panel);color:var(--ink);display:flex;flex-direction:column;
  align-items:flex-start;padding:clamp(26px,3.4vw,52px) clamp(26px,4vw,64px) clamp(26px,4vh,48px);
  min-width:0;
}
.gate-body{max-width:26rem;width:100%;margin-top:auto;padding-top:clamp(36px,7vh,80px)}
.signin .est{margin:clamp(26px,5vh,50px) 0 0;font-size:.64rem;letter-spacing:.3em;text-transform:uppercase;color:var(--dim)}
.signin .eyebrow{
  font-size:.66rem;font-weight:500;letter-spacing:.34em;text-transform:uppercase;
  color:var(--mute);margin:0 0 clamp(14px,2.4vh,22px);
}
.gate-title{
  font-family:var(--serif);font-weight:400;font-size:clamp(1.9rem,3.4vw,3.1rem);
  line-height:1.06;letter-spacing:-.02em;color:var(--ink);
  margin:0 0 clamp(26px,4vh,42px);max-width:15ch;
}
.gate-title em{font-style:italic;color:var(--gold)}
.hl{display:block;overflow:hidden}
.hl>span{display:block;animation:hlin .95s var(--ease) both}
.gate-title.hl>span{animation-delay:.1s}
@keyframes hlin{from{transform:translateY(112%)}to{transform:none}}

.gate form{
  display:flex;flex-direction:column;align-items:flex-start;gap:clamp(18px,2.6vh,24px);
  width:100%;animation:rowin .8s var(--ease) both;animation-delay:.34s;
}
.gf{min-width:0;width:100%}
.gf label{
  display:block;font-size:.62rem;font-weight:500;letter-spacing:.26em;
  text-transform:uppercase;color:var(--mute);margin-bottom:7px;
}
.gf input{
  width:100%;padding:9px 2px;border:0;border-bottom:1px solid var(--line-2);
  background:none;border-radius:0;font-size:1rem;color:var(--ink);
  transition:border-color .3s var(--ease);
}
.gf input:focus{outline:none;border-bottom-color:var(--gold)}
/* Chrome repaints an autofilled field and keeps the author colour: on a dark
   ground that renders white on near white */
.gf input:-webkit-autofill,.gf input:-webkit-autofill:focus{
  -webkit-text-fill-color:var(--ink);
  box-shadow:0 0 0 60px var(--panel) inset;
  caret-color:var(--ink);
}
.signin .btn{
  display:inline-flex;align-items:center;gap:1.1rem;padding:1.15rem 2.6rem;
  background:var(--gold);color:#0B1220;border:0;cursor:pointer;
  font-size:.72rem;font-weight:500;letter-spacing:.24em;text-transform:uppercase;
  transition:background .3s var(--ease),transform .16s var(--ease);
}
.signin .btn:hover{background:#dcc48f}
.signin .btn:active{transform:scale(.97)}
.signin .btn span{transition:transform .3s var(--ease)}
.signin .btn:hover span{transform:translateX(6px)}
.signin .btn[disabled]{opacity:.55;cursor:default}
.gate-note{margin:0;min-height:1.4em;font-size:.8rem;color:var(--late)}
.gate-panel .bars i{background:var(--ink);height:3.5px;width:34px;gap:3.5px}
.gate-panel .bars{gap:3.5px}
.gate-panel .bars i:nth-child(3){background:var(--gold)}
.gate-panel .brand-name,.gate-panel .wordmark{
  color:var(--ink);font-size:.88rem;font-weight:500;letter-spacing:.42em;text-transform:uppercase;
}
.gate-panel .logo{display:flex;align-items:center;gap:.95rem;text-decoration:none}

@media(max-width:820px){
  .gate{grid-template-columns:1fr;grid-template-rows:26svh 1fr}
  .gate-plate::after{background:linear-gradient(to bottom,rgba(11,18,32,0) 60%,rgba(11,18,32,.4) 100%)}
  .gate-body{padding-top:clamp(24px,5vh,48px)}
  .gate-title{font-size:clamp(1.8rem,7vw,2.6rem)}
}
