/* ─────────────────────────────────────────────────────────────────────────
   system.css — the design system for Noti Platform V2.

   Tokens and primitives, nothing product-specific. Step 1 of the build order
   in PRODUCT-UI.md §21. It loads AFTER noti.css and app.css and adds; it
   replaces nothing yet, so the current application is untouched while screens
   move across one at a time.

   Everything here is §17 (tokens) and §8 (patterns) of that contract.

   ── the contrast audit, which found four real problems ─────────────────
   §18 asks for 4.5:1 on body text. The existing palette was measured rather
   than assumed, against --cream #F7F3ED:

     --ink      16.26:1   fine
     --mid       6.80:1   fine
     --grey      3.79:1   FAILS body, passes large
     --faint     2.38:1   fails everything
     --orange    2.95:1   fails everything, as TEXT
     white on --orange    3.27:1   FAILS — and that is the primary button

   The last one matters most: the most-used control in the product does not
   meet contrast. --orange-d (4.37:1) does not fix it either. So:

     · --orange stays exactly as it is for LARGE, BOLD marks and for fills
       behind DARK text, where it measures 5.51:1 and looks like Noti
     · --orange-btn #4B3CA8 (8.6:1 with white; violet since 12 Nov 2026) is what a filled button uses
     · --text-2 #6F6459 (5.21:1) replaces --grey for body-size secondary text
     · --grey is demoted to large text only; --faint to decoration only

   The brand does not change. One token is added for the one place the brand
   colour was being asked to do something it cannot do.
   ───────────────────────────────────────────────────────────────────────── */

:root{
  /* ── space. Seven steps, nothing between them ─────────────────────────
     A value not on this scale is a decision somebody made without thinking
     about the ones either side of it. */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px; --s7:48px;

  /* ── type. Four sizes on screen at once, maximum ──────────────────────── */
  --t-page:28px;  --t-page-lh:34px;  --t-page-w:800;
  --t-sect:17px;  --t-sect-lh:24px;  --t-sect-w:700;
  --t-body:14.5px;--t-body-lh:21px;  --t-body-w:500;
  --t-small:12.5px;--t-small-lh:18px;--t-small-w:600;

  /* ── colour that the existing palette does not safely provide ─────────── */
  --text-2:#6F6459;      /* secondary text at BODY size — 5.21:1 on cream   */
  --orange-btn:#4B3CA8;  /* filled button with white text — 8.6:1 (violet)  */
  --mint-d2:#17633C;     /* the mint chip at 5.94:1; --mint-d was 4.34:1    */
  --teal-d:#0F6B74;      /* the one figure on Home that is not ink — 5.63:1 */

  /* ── density ──────────────────────────────────────────────────────────── */
  --row:44px;            /* desktop table row                               */
  --row-touch:56px;      /* the same row where a finger is using it         */
  --tap:44px;            /* smallest interactive target, anywhere           */

  --dialog-w:460px;       /* one form, centred. §8            */
}

/* Cold hands, standing up, outside. §9. */
@media (pointer:coarse){ :root{ --row:var(--row-touch); } }

/* The UA's own [hidden]{display:none} is the weakest rule in the cascade, so
   ANY display of ours beats it — a menu with display:flex and hidden set was
   permanently open, and every future element that toggles `hidden` and also
   has a display would go the same way. Stated once, here, so it cannot. */
[hidden]{ display:none !important }

/* ── focus. Never removed, never invisible ────────────────────────────────
   Removing a focus ring is the single most common accessibility failure in
   business software, and the people using Noti all day are the ones who
   navigate by keyboard. */
.sys :focus-visible{ outline:2.5px solid var(--orange-btn); outline-offset:2px;
  border-radius:var(--r3) }

@media (prefers-reduced-motion:reduce){
  .sys *, .sys *::before, .sys *::after{
    animation-duration:.01ms !important; transition-duration:.01ms !important }
}


/* ═══════════════════════════════════════════════════════════════════════
   PAGE — the frame every area and object page sits in
   ═══════════════════════════════════════════════════════════════════════ */

/* ── density. The header is a header, not a title screen ──────────────
   This was four generous rows — crumb, a 28px name, the one line, a chip on
   a row of its own — before a single fact appeared, and 24px of air between
   every block after it. On a 900px laptop that is most of the fold spent on
   furniture.

   A business tool is read, not admired. The title steps down to 21px, the
   rows tighten to 10-12px, and the status chip moves up beside the name
   where it has always belonged: it is part of the identity, not a separate
   announcement. Nothing is removed — it is the same page, closer together.

   These are the shared numbers, so every area gets it, not just this one. */
/* `width:100%` is not decoration. .sys-page is a flex child of .app, and a
   flex child shrink-to-fits — so a section with short content collapsed to
   its content. Settings' plan section rendered 249px wide on a 1280px
   screen while the business section rendered 800px, which makes nine
   sections of one pane look like nine different pages.

   Same failure as the Subject page's measure on 22 September: margin-inline
   auto on a flex child that never claimed its width. */
.sys-page{ padding-block:18px; display:flex; flex-direction:column; gap:14px;
  width:100%; min-width:0 }
.sys-head{ display:flex; align-items:center; gap:12px; flex-wrap:wrap }
.sys-head .t{ flex:1 1 280px; min-width:0 }
.sys-h1{ font-size:21px; line-height:27px; font-weight:800;
  letter-spacing:-.02em; display:flex; align-items:center; gap:10px;
  flex-wrap:wrap }
/* The one line under the title. Three things somebody needs to decide what to
   do — not metadata. §7. */
.sys-sub{ font-size:13px; line-height:18px; font-weight:500;
  color:var(--text-2); margin-top:2px }
.sys-crumb{ font-size:11.5px; font-weight:700; letter-spacing:.02em;
  color:var(--text-2); display:inline-flex; align-items:center; gap:5px;
  background:none; border:0; cursor:pointer; padding:0 }
.sys-crumb:hover{ color:var(--ink) }
.sys-crumb svg{ width:13px; height:13px }

.sys-sect{ display:flex; flex-direction:column; gap:var(--s3) }
.sys-sect > h2{ font-size:var(--t-sect); line-height:var(--t-sect-lh);
  font-weight:var(--t-sect-w); letter-spacing:-.02em }


/* ═══════════════════════════════════════════════════════════════════════
   TABLE — a strength, not a fallback
   Most business software has bad tables and the people who live in Noti all
   day will notice good ones. §8.
   ═══════════════════════════════════════════════════════════════════════ */

.sys-tw{ overflow-x:auto; border-radius:var(--r2); background:var(--white) }
.sys-t{ width:100%; border-collapse:collapse; font-size:var(--t-body) }
.sys-t th{ position:sticky; top:0; z-index:1; background:var(--white);
  text-align:left; font-size:10.5px; font-weight:800;
  color:var(--text-2); letter-spacing:.1em; text-transform:uppercase;
  padding:9px var(--s4); border-bottom:1px solid var(--line);
  white-space:nowrap }
.sys-t td{ padding:0 var(--s4); height:38px;
  border-bottom:1px solid var(--line-2); vertical-align:middle }
/* A short cell ("5 days ago") breaking over two lines doubles the row for
   nothing; cells that should wrap say .wrap. */
.sys-t td:not(.wrap):not(:first-child){ white-space:nowrap }
@media (max-width:1099px){ .sys-t .wide-only{ display:none } .sys-t td, .sys-t th{ padding-inline:10px } }
@media (max-width:1439px){ .sys-t .xl-only{ display:none } }
@media (max-width:1099px){ .sys-t .lg-only{ display:none } }
@media (min-width:1440px){ .sys-t .lg-only{ display:none } .sys-t .cust-name .m .cust-sub{ display:none } }
@media (pointer:coarse){ .sys-t td{ height:var(--row-touch) } }
.sys-t tr:last-child td{ border-bottom:0 }
.sys-t tbody tr{ cursor:pointer }
.sys-t tbody tr:hover{ background:var(--cream-2) }
.sys-t tbody tr[aria-selected="true"]{ background:var(--orange-l) }

/* Money and quantity line up or they are useless for comparison. */
.sys-t .num{ text-align:right; font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1; white-space:nowrap }
.sys-t th.num{ text-align:right }
.sys-t .mono{ font-family:var(--m); font-variant-numeric:tabular-nums }
.sys-t .wrap{ white-space:normal }
.sys-t .act{ width:1%; white-space:nowrap; text-align:right }

.sys-t .sort{ background:none; border:0; font:inherit; color:inherit;
  cursor:pointer; display:inline-flex; align-items:center; gap:4px;
  text-transform:inherit; letter-spacing:inherit; font-weight:inherit }
.sys-t .sort[aria-sort]:not([aria-sort="none"]){ color:var(--ink) }

/* The same list on a phone. Not the table squeezed — a different shape. §9 */
.sys-rows{ display:flex; flex-direction:column; background:var(--white);
  border-radius:var(--r2); overflow:hidden }
.sys-row{ display:flex; align-items:center; gap:var(--s3);
  min-height:var(--row-touch); padding:var(--s3) var(--s4);
  border-bottom:1px solid var(--line-2); cursor:pointer; text-align:left;
  background:none; border-left:0; border-right:0; border-top:0; width:100%;
  font:inherit; color:inherit }
.sys-row:last-child{ border-bottom:0 }
.sys-row:hover{ background:var(--cream-2) }
.sys-row .m{ flex:1; min-width:0 }
.sys-row .m b{ display:block; font-size:var(--t-body); font-weight:700;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.sys-row .m span{ display:block; font-size:var(--t-small); color:var(--text-2);
  font-weight:var(--t-small-w) }
/* A chip on the second line is still a chip: the rule above made it a
   full-width green bar under a job's name (walk, 26 Sep). */
.sys-row .m span.sys-chip{ display:inline-flex; width:auto; max-width:100% }
.sys-row .r{ text-align:right; font-variant-numeric:tabular-nums; flex:none }


/* ═══════════════════════════════════════════════════════════════════════
   CHIP — status is a WORD, never a coloured dot
   A dot is unreadable to eight percent of men and ambiguous to everybody
   else. §12.
   ═══════════════════════════════════════════════════════════════════════ */

.sys-chip{ display:inline-flex; align-items:center; gap:6px;
  padding:3px 10px; border-radius:99px; font-size:var(--t-small);
  font-weight:700; letter-spacing:-.01em; white-space:nowrap;
  background:var(--line-2); color:var(--mid) }
.sys-chip.go{   background:var(--mint);   color:var(--mint-d2) }
.sys-chip.wait{ background:var(--butter); color:var(--butter-d) }
.sys-chip.warn{ background:var(--peach);  color:var(--peach-d) }
.sys-chip.info{ background:var(--sky);    color:var(--sky-d) }
.sys-chip.calm{ background:var(--lav);    color:var(--lav-d) }


/* ═══════════════════════════════════════════════════════════════════════
   BUTTONS — one primary per view
   ═══════════════════════════════════════════════════════════════════════ */

/* 36px with a mouse, 44 with a finger.

   --tap is the smallest thing a cold hand standing outside can hit, and it
   is right — but applying it to a desktop header put a 44px pill and a 44px
   circle beside a 28px heading, which read as a toolbar rather than as two
   quiet actions. The floor only has to be a floor where a finger is doing
   the work, and the pointer says which that is. §9 */
.sys-b{ display:inline-flex; align-items:center; justify-content:center;
  gap:6px; min-height:36px; padding:0 14px; white-space:nowrap;
  border-radius:99px; border:1.5px solid transparent; cursor:pointer;
  font-family:inherit; font-size:13.5px; font-weight:700;
  letter-spacing:-.01em; transition:background .15s, border-color .15s,
  color .15s }
.sys-b svg{ width:15px; height:15px; flex:none }

/* ── a thumb is not a pointer ─────────────────────────────────────────────
   36px is a fine button under a mouse and a poor one under a thumb, and the
   difference is not a preference — it is the width of the screen, which is
   the one thing that legitimately decides layout.

   So the system button, the chips and the small buttons grow on a phone and
   are left exactly alone on a laptop. Ninety .sys-b across the product all
   get this, which is the point: it is a property of the control, not of the
   screen that happens to be using it, and fixing it in Settings alone would
   have been fixing the place it was measured rather than the thing that was
   wrong. */
/* .chip and .btn are NOT here. They are defined in styles/noti.css, and
   reaching across to resize them from this sheet is the exact shape of the
   .ask collision — a second sheet deciding layout for a component that
   belongs to another. check-classes caught it within a minute of writing
   it, which is the first time that guard has caught me rather than the
   other way round. They are overridden where they live. */
@media (max-width:560px){
  .sys-b{ min-height:44px; padding:0 16px }
}
.sys-b.primary{ background:var(--orange-btn); color:#fff }
.sys-b.primary:hover{ background:var(--orange-d) }
.sys-b.quiet{ background:var(--white); border-color:var(--line);
  color:var(--ink) }
.sys-b.quiet:hover{ border-color:var(--ink) }
.sys-b.bare{ background:none; color:var(--text-2); padding:0 var(--s2) }
.sys-b.bare:hover{ color:var(--ink) }
.sys-b:disabled{ opacity:.5; cursor:not-allowed }
.sys-b.wide{ width:100% }

/* Everything that is not the primary action. §7. */
.sys-more{ width:34px; height:34px; border-radius:50%;
  border:1.5px solid var(--line); background:var(--white); cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center;
  color:var(--text-2); flex:none }
.sys-more svg{ width:16px; height:16px }
.sys-more:hover{ border-color:var(--ink); color:var(--ink) }

/* The actions never stretch and never wrap away from each other. */
.sys-head .acts{ display:flex; align-items:center; gap:8px; flex:none }

@media (pointer:coarse){
  .sys-b{ min-height:var(--tap); padding:0 var(--s4); font-size:var(--t-body) }
  .sys-more{ width:var(--tap); height:var(--tap) }
  .sys-more svg{ width:18px; height:18px }
  /* the way back, a note's Delete and a linked record were 15-35px under a
     thumb (run-throughs, 1 Oct) */
  .sys-crumb, .mute, .linkrow{ min-height:var(--tap); display:inline-flex; align-items:center }
  .linkrow{ display:flex }
}


/* ═══════════════════════════════════════════════════════════════════════
   DIALOGUE — centred, and only as tall as what is in it

   This was a right-hand drawer, on the reasoning that what is being edited
   usually refers to what is behind it. That is true of an invoice line and
   false of most things: a three-field form stretched down 900px of empty
   column, and the record it referred to was behind the sheet anyway.

   Centred, sized to its contents, scrolling its own body when there is
   genuinely a lot. A phone gets a sheet from the bottom edge — a centred box
   is one that jumps when the keyboard opens, and the bottom is where a thumb
   already is. §8 §9
   ═══════════════════════════════════════════════════════════════════════ */

.sys-scrim{ position:fixed; inset:0; z-index:60; background:rgba(23,27,24,.42);
  -webkit-backdrop-filter:blur(2px); backdrop-filter:blur(2px);
  opacity:0; transition:opacity .2s; display:flex;
  align-items:center; justify-content:center; padding:24px }
.sys-scrim.in{ opacity:1 }
.sys-drawer{ position:relative; z-index:61;
  width:min(var(--dialog-w), 100%); max-height:min(86vh, 760px);
  background:var(--cream); border-radius:18px;
  box-shadow:0 30px 70px -24px rgba(23,27,24,.5);
  display:flex; flex-direction:column;
  transform:translateY(10px) scale(.99); opacity:0;
  transition:transform .2s cubic-bezier(.22,1,.36,1), opacity .2s }
.sys-drawer.in{ transform:none; opacity:1 }
.sys-drawer > header{ display:flex; align-items:center; gap:var(--s3);
  padding:18px 20px 12px; flex:none }
.sys-drawer > header h2{ flex:1; font-size:19px; font-weight:800;
  letter-spacing:-.02em; min-width:0 }
.sys-drawer > .body{ flex:1 1 auto; min-height:0; overflow-y:auto;
  padding:2px 20px 18px; display:flex; flex-direction:column; gap:13px }
.sys-drawer > footer{ padding:13px 20px; border-top:1px solid var(--line);
  display:flex; gap:9px; flex:none; border-radius:0 0 18px 18px }
.sys-drawer > footer .sys-b{ flex:1 }

@media (max-width:700px){
  .sys-scrim{ align-items:flex-end; padding:0 }
  .sys-drawer{ width:100vw; max-height:92vh;
    border-radius:var(--r) var(--r) 0 0; transform:translateY(100%) scale(1) }
  .sys-drawer.in{ transform:none }
  .sys-drawer > footer{ border-radius:0;
    padding-bottom:calc(13px + env(safe-area-inset-bottom)) }
}


/* ═══════════════════════════════════════════════════════════════════════
   FORM — one column, labels above, errors in words
   ═══════════════════════════════════════════════════════════════════════ */

.sys-f{ display:flex; flex-direction:column; gap:var(--s4) }
.sys-fl{ display:flex; flex-direction:column; gap:6px }
.sys-fl > label{ font-size:var(--t-small); font-weight:700; color:var(--mid) }
.sys-fl input, .sys-fl select, .sys-fl textarea{
  font-family:inherit; font-size:var(--t-body); color:var(--ink);
  background:var(--white); border:1.5px solid var(--line);
  border-radius:var(--r3); padding:0 var(--s3); min-height:var(--tap);
  outline:none; width:100% }
.sys-fl textarea{ padding:var(--s3); min-height:96px; resize:vertical;
  line-height:var(--t-body-lh) }
.sys-fl input:focus, .sys-fl select:focus, .sys-fl textarea:focus{
  border-color:var(--orange-btn) }
.sys-fl .hint{ font-size:var(--t-small); color:var(--text-2);
  font-weight:var(--t-small-w) }
/* Never a red border alone — a border is not a sentence. */
.sys-fl.bad input, .sys-fl.bad select, .sys-fl.bad textarea{
  border-color:var(--peach-d) }
.sys-fl .err{ font-size:var(--t-small); font-weight:700; color:var(--peach-d) }


/* ═══════════════════════════════════════════════════════════════════════
   EMPTY — a real design surface
   A business's first week is mostly empty states, and they are the only
   teaching Noti gets to do. §13.
   ═══════════════════════════════════════════════════════════════════════ */

.sys-empty{ background:var(--white); border-radius:var(--r2);
  padding:var(--s7) var(--s5); text-align:center;
  display:flex; flex-direction:column; align-items:center; gap:var(--s3) }
.sys-empty .ic{ width:44px; height:44px; border-radius:50%;
  background:var(--cream); display:flex; align-items:center;
  justify-content:center; color:var(--text-2) }
.sys-empty h3{ font-size:var(--t-sect); font-weight:var(--t-sect-w) }
.sys-empty p{ font-size:var(--t-body); line-height:var(--t-body-lh);
  color:var(--text-2); max-width:44ch }

/* The quieter offer under the obvious one. Smaller and set apart, so an empty
   screen still answers "what do I do here" with one thing. */
.sys-empty p.second{ font-size:13px; margin-top:calc(var(--s2) * -1) }

/* Same offer, in the catalogue, which draws its own empty row rather than
   using sys-empty. */
.emptymore{ text-align:center; font-size:13px; color:var(--text-2);
  padding:0 var(--s5) var(--s5); line-height:1.6; max-width:52ch; margin:0 auto }

/* The one offer on a first morning. Sits under the hero, reads as a note
   rather than an alert — nothing is wrong, and a business that means to type
   its customers in by hand is not making a mistake. Dismissed for good. */
.bringdata{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--s4);
  justify-content:space-between; background:var(--white);
  border:1px solid var(--line); border-radius:var(--r2);
  padding:var(--s4) var(--s5); margin:var(--s4) 0 0 }
.bringdata .bd{ min-width:min(100%, 22rem); flex:1 1 22rem }
.bringdata .bd b{ display:block; font-size:14.5px }
.bringdata .bd span{ display:block; font-size:13px; color:var(--text-2);
  line-height:1.55; margin-top:3px; max-width:56ch }
.bringdata .ax{ display:flex; gap:var(--s2); flex-wrap:wrap }

/* Nothing needs you. Good news, drawn as good news. §3. */
.sys-empty.clear .ic{ background:var(--mint); color:var(--mint-d2) }

/* Not built yet — says so, and takes no money. §13. */
.sys-empty.unbuilt{ border:1px dashed var(--line); background:var(--cream-2) }


/* ═══════════════════════════════════════════════════════════════════════
   NOTICED — the engine's shape, and the only shape it has
   Noti noticed → why it matters → what changed → what Noti did → what needs
   you. There is no Insights screen; this appears on Home and object pages
   and nowhere else. §4b.
   ═══════════════════════════════════════════════════════════════════════ */

.sys-noticed{ background:var(--white); border-radius:var(--r2);
  padding:var(--s4); display:flex; flex-direction:column; gap:var(--s3) }
.sys-noticed > h3{ font-size:var(--t-sect); font-weight:var(--t-sect-w);
  letter-spacing:-.02em }
/* Beat 2 and 3: why it matters, and what changed. Plain sentences — a metric
   without a consequence is not a reason to act. */
.sys-noticed .said{ display:flex; flex-direction:column; gap:var(--s1);
  font-size:var(--t-body); line-height:var(--t-body-lh); color:var(--mid) }
.sys-noticed .said b{ color:var(--ink); font-weight:700 }
/* Beat 4: what Noti did, or recommends. Never silent. */
.sys-noticed .did{ font-size:var(--t-small); font-weight:var(--t-small-w);
  color:var(--text-2); padding-top:var(--s1) }
.sys-noticed .did b{ color:var(--ink) }
/* Beat 5: one action, and a way to say no. A signal you cannot dismiss
   becomes noise, then becomes furniture. */
.sys-noticed footer{ display:flex; gap:var(--s2); flex-wrap:wrap;
  padding-top:var(--s1) }

/* On an object page it is inline rather than a card of its own. */
.sys-noticed.inline{ background:var(--cream-2); padding:var(--s3) var(--s4) }


/* ═══════════════════════════════════════════════════════════════════════
   OBJECT PAGE — learn the anatomy once. §7.
   ═══════════════════════════════════════════════════════════════════════ */

.sys-tabs{ display:flex; gap:var(--s1); border-bottom:1px solid var(--line);
  overflow-x:auto; scrollbar-width:none }
.sys-tabs::-webkit-scrollbar{ display:none }
.sys-tab{ background:none; border:0; border-bottom:2.5px solid transparent;
  padding:7px 11px; margin-bottom:-1px; cursor:pointer;
  font-family:inherit; font-size:13.5px; font-weight:700;
  color:var(--text-2); white-space:nowrap; min-height:34px }
@media (pointer:coarse){ .sys-tab{ min-height:var(--tap); padding:0 13px } }
.sys-tab:hover{ color:var(--ink) }
.sys-tab[aria-selected="true"]{ color:var(--ink);
  border-bottom-color:var(--orange) }


/* ═══════════════════════════════════════════════════════════════════════
   LAYOUT — the layout CHANGES, it does not shrink. §19.
   ═══════════════════════════════════════════════════════════════════════ */

.sys-cols{ display:grid; gap:var(--s4); grid-template-columns:1fr }
@media (min-width:1100px){
  .sys-cols.two{ grid-template-columns:1fr 1fr }
  .sys-cols.side{ grid-template-columns:minmax(0,1fr) 340px }
}
/* Below 700, the table becomes rows and the rows are what is drawn. */
@media (max-width:699px){ .sys-tw{ display:none } }
@media (min-width:700px){ .sys-rows.only-narrow{ display:none } }


/* ═══════════════════════════════════════════════════════════════════════
   THE DOT — Noti's presence. §0c.

   The orange dot in the wordmark, promoted from decoration to the thing that
   shows Noti is there. NOT a mascot: no face, no eyes, nothing that could be
   read as a character. The restraint is the idea — the moment it gets a face
   it is a chatbot avatar and the product ages five years.

   Every animation here is ONE-SHOT. Nothing loops, nothing breathes
   permanently. A thing that moves because it CHANGED is alive; a thing that
   moves because it exists is a distraction, and by week two it is a setting
   somebody wants to turn off.
   ═══════════════════════════════════════════════════════════════════════ */

.dot{ width:7px; height:7px; border-radius:50%; background:var(--orange);
  display:inline-block; flex:none; vertical-align:baseline }
.dot.lg{ width:10px; height:10px }

/* Once, when something genuinely needs a person. Three beats and it stops —
   a permanent pulse is an alarm, and an alarm nobody can silence gets ignored. */
@keyframes dot-notice{
  0%,100%{ transform:scale(1);   box-shadow:0 0 0 0 rgba(176,62,20,.45) }
  40%    { transform:scale(1.5); box-shadow:0 0 0 6px rgba(176,62,20,0) }
}
.dot.notice{ background:var(--attn); animation:dot-notice 1.1s ease-out 3 }  /* needs a person: warm, not the accent */

/* Thinking. Replaces a spinner: same job, and it is Noti doing it rather than
   a generic circle borrowed from every other product. */
@keyframes dot-think{
  0%,100%{ opacity:.35; transform:scale(.8) }
  50%    { opacity:1;   transform:scale(1.1) }
}
.dot.think{ animation:dot-think .9s ease-in-out infinite }

/* Beside something Noti did on its own, in a trail. Calmer and smaller. */
.dot.did{ background:var(--mint-d2); width:6px; height:6px }
.dot.held{ background:var(--lav-d);  width:6px; height:6px }
.dot.failed{ background:var(--peach-d); width:6px; height:6px }

@media (prefers-reduced-motion:reduce){
  .dot.notice, .dot.think{ animation:none }
}
/* ═══════════════════════════════════════════════════════════════════════
   HOME — the approved design.

   Three surfaces and no more: one dark hero carrying Noti's voice, a wide
   left column of work, a narrow right column of what Noti is holding. Under
   the hero nothing is a card except the single closing note, because a field
   of white rectangles is how every other product in this market looks.

   The measure is deliberate. The composition was drawn at about 900px of
   stage; handed a whole monitor it stretches into a line of copy alone
   across a metre of black. Home is prose and composition, not rows.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── the measure ──────────────────────────────────────────────────────
   No cap. Home fills whatever stage it is given, because a fixed maximum is
   only ever right for one window: somebody running the browser at 75% has
   2000px of viewport, and a 1500px cap leaves a quarter of their screen as
   dead cream down the right-hand side. Everyone's window is different and it
   all has to fit.

   What made the earlier build look stretched was never the width — it was a
   design with no left bars, no divider and no second-column weight, so a wide
   screen had nothing holding it together. What holds it is below: a hairline
   between the columns, and a right column narrow enough that the left one
   keeps a reading measure at any width. */

/* ── THE HERO ─────────────────────────────────────────────────────────
   The only branded surface on the screen, and the only place the orange is
   allowed to be decoration rather than a signal. */
/* ── the hero holds ───────────────────────────────────────────────────
   It is the status. Scrolling to read the list should not take the status
   off the screen — that is the one thing on Home you want to still be true
   while you are working through what is under it.

   And it CONDENSES rather than parking a 190px slab over the page: once it
   is stuck the orbit, the creed and the sub-line go, and what stays is the
   sentence and the dot. Two states of one surface, which is the same idea
   the Arcade uses on the same rectangle. */
.home-hero{ background:var(--ink); border-radius:16px; color:#fff;
  padding:22px 30px 20px; position:sticky; top:14px; z-index:20;
  overflow:hidden;
  transition:padding .22s cubic-bezier(.2,.8,.2,1) }
.home-hero.stuck{ padding:13px 30px 13px }
.home-hero.stuck .home-creed,
.home-hero.stuck .home-sub,
.home-hero.stuck .home-orbit{ display:none }
.home-hero.stuck .home-when{ display:inline; margin-right:12px; opacity:.55 }
.home-hero.stuck .home-said{ font-size:20px; line-height:26px; margin-top:0;
  gap:11px; display:inline-flex; vertical-align:middle }
.home-hero.stuck .home-said .dot{ width:9px; height:9px }
/* gone, not dimmed: a 400px glow clipped to a 52px bar stops reading as a
   soft edge and starts reading as a lighter rectangle pasted on the right. */
.home-hero.stuck::after{ opacity:0 }
.home-hero::after{ transition:opacity .22s }
@media (prefers-reduced-motion:reduce){ .home-hero{ transition:none } }

/* the 1px marker that says whether the hero has left its place */
.home-top{ height:1px; margin-bottom:-1px }

/* the glow. Off-canvas and enormous, so what lands on the panel is the soft
   edge of something rather than a circle sitting on it */
/* Big, soft, and mostly off the panel — what lands is the warm edge of
   something rather than a circle sitting on the surface. */
.home-hero::after{ content:''; position:absolute; right:-120px; top:-150px;
  width:400px; height:400px; border-radius:50%; pointer-events:none;
  background:radial-gradient(circle at 40% 60%,
    rgba(75,60,168,.52), rgba(75,60,168,.16) 42%, transparent 70%) }

.home-when{ font-size:11px; font-weight:800; color:rgba(255,255,255,.44);
  letter-spacing:.13em; text-transform:uppercase; position:relative; z-index:1 }

.home-said{ font-size:29px; line-height:35px; font-weight:800;
  letter-spacing:-.035em; margin-top:7px; display:flex; align-items:center;
  gap:15px; position:relative; z-index:1 }
.home-said .dot{ width:11px; height:11px }

.home-sub{ font-size:14px; color:rgba(255,255,255,.7); margin-top:5px;
  font-weight:500; position:relative; z-index:1 }

/* ── what Noti is, said once, quietly ──────────────────────────────────
   Four short lines in the corner the glow already owns. It is the only place
   on Home that explains the product rather than reporting on the business,
   and it is deliberately the quietest text on the screen. */
.home-creed{ position:absolute; right:30px; top:24px; z-index:1;
  text-align:right; font-size:11.5px; line-height:17px; font-weight:600;
  color:rgba(255,255,255,.52); max-width:150px }
.home-creed b{ display:block; color:rgba(255,255,255,.8); font-weight:700 }

/* ── THE ORBIT ────────────────────────────────────────────────────────
   Four figures on one line system, with a node on each connector: the thing
   that says these are CONNECTED rather than four numbers that happen to sit
   in a row. Rules for every count — at one it is a sentence, at zero it is
   not drawn, because a row of zeroes is the worst possible first impression. */
.home-orbit{ display:flex; align-items:flex-end; margin-top:16px;
  position:relative; z-index:1; flex-wrap:wrap; gap:0 }
.home-orbit .n{ display:flex; flex-direction:column; gap:3px; flex:none }
.home-orbit .n b{ font-size:22px; font-weight:800; letter-spacing:-.035em;
  font-variant-numeric:tabular-nums; line-height:26px }
.home-orbit .n span{ font-size:10px; font-weight:800;
  color:rgba(255,255,255,.44); text-transform:uppercase; letter-spacing:.13em }
/* Capped. With two signals instead of four an uncapped connector flings the
   nodes to opposite ends of a metre-wide panel and the line between them
   stops reading as a relationship — it reads as a gap. The cap keeps the
   orbit a group at any count, left-packed, whatever the window. */
.home-orbit .lnk{ flex:1 1 auto; max-width:260px; height:1px;
  background:rgba(255,255,255,.15); margin:0 26px 13px; min-width:30px;
  position:relative }
.home-orbit .lnk::before{ content:''; position:absolute; left:50%; top:50%;
  width:4px; height:4px; margin:-2px 0 0 -2px; border-radius:50%;
  background:rgba(255,255,255,.34) }
/* a light runs the line every eight seconds — one-shot per cycle, never a
   permanent shimmer */
.home-orbit .lnk::after{ content:''; position:absolute; top:0; left:-30%;
  width:30%; height:1px; background:linear-gradient(90deg, transparent,
  rgba(75,60,168,.9), transparent); animation:home-travel 8s linear infinite }
.home-orbit .lnk:nth-of-type(4)::after{ animation-delay:.35s }
.home-orbit .lnk:nth-of-type(6)::after{ animation-delay:.7s }
@keyframes home-travel{ 0%{left:-30%} 22%{left:100%} 100%{left:100%} }
@media (prefers-reduced-motion:reduce){ .home-orbit .lnk::after{ animation:none } }

/* one signal: a sentence, not a grid with one cell in it */
.home-one{ margin-top:22px; font-size:14px; color:rgba(255,255,255,.72);
  font-weight:600; display:flex; align-items:center; gap:10px;
  position:relative; z-index:1 }
.home-one b{ font-weight:800; color:#fff }


/* ── THE TWO COLUMNS ──────────────────────────────────────────────────
   Asymmetric on purpose: what needs a person is wider than what Noti is
   already holding. */
.home{ display:grid; gap:14px; grid-template-columns:1fr; margin-top:14px }
/* From a tablet up (LAYOUT.md): an iPad has room for both columns, and
   the phone's one long column there left half of what Noti holds below the
   fold. The tablet's ratio is a little more even, so the side cards keep a
   readable width at 820. */
@media (min-width:700px){
  .home{ grid-template-columns:minmax(0,1.3fr) minmax(0,1fr);
         align-items:start; gap:14px }
}
@media (min-width:1100px){
  .home{ grid-template-columns:minmax(0,1.58fr) minmax(0,1fr); gap:16px }
}
.home-main, .home-side{ display:flex; flex-direction:column; gap:14px;
  min-width:0 }

/* ── THE CARD ─────────────────────────────────────────────────────────
   The hairline between the two columns is gone, and this is what replaced
   it. A rule down the middle told you where the page folded; it could not
   tell you where one thing ended and the next began, which is the question
   once the blocks can be moved. A card can. It is also the only shape that
   makes "this is a thing you can pick up" legible without a single word of
   instruction. */
/* One surface, two users. Home invented it; the object pages want the same
   thing, and a second class that merely looks like it is how two screens
   drift apart over a fortnight. Home-specific behaviour stays on .hcard. */
.sys-card, .hcard{ background:var(--white); border:1px solid var(--line);
  border-radius:var(--r3); padding:14px 16px 15px; min-width:0 }
.hcard > .sys-sect{ gap:0 }

.sys-card > .sys-sect{ gap:0 }
/* The same 11px label Home uses, and the same one the figures wear. A card
   heading at section size competes with the page title for the same job. */
.sys-card > .sys-sect > h2{ font-size:10.5px; font-weight:800;
  letter-spacing:.12em; text-transform:uppercase; color:var(--text-2);
  line-height:13px; margin-bottom:9px }

/* A column of cards, or two. Used by every object page from here on. */
.sys-cards{ display:flex; flex-direction:column; gap:10px; min-width:0 }
.sys-deck{ display:grid; gap:10px; grid-template-columns:1fr; align-items:start }
@media (min-width:860px){
  .sys-deck{ grid-template-columns:minmax(0,1.35fr) minmax(0,1fr) }
}

.home .sys-sect{ gap:0 }
.home .sys-sect > h2{ font-size:11px; font-weight:800; letter-spacing:.13em;
  text-transform:uppercase; color:var(--text-2); line-height:14px;
  margin-bottom:10px }

/* The closing note carries its own surface; inside a card that is one box
   inside another box saying the same thing. */
.hcard .s-note{ margin:-17px -20px -18px }
.hcard .home-note{ border:0; border-radius:var(--r3); background:transparent }


/* ── ARRANGING ────────────────────────────────────────────────────────
   A mode, not a permanent set of handles. Handles on every card all day
   would be six controls competing with the work on a screen whose whole
   claim is that it shows you the work first. */
.home-arrange{ display:flex; align-items:center; justify-content:flex-end;
  gap:14px; margin-top:18px; min-height:30px }
/* While you are arranging, it follows you. Everything above it can grow by
   six cards' worth of tools, and hunting for Done is the one thing that
   would make a person leave the mode half-finished. */
.home-arrange.stuck{ position:sticky; bottom:14px; z-index:3;
  background:var(--cream); border-radius:999px;
  box-shadow:0 0 0 8px var(--cream), 0 6px 22px rgba(23,27,24,.09) }
.home-edit, .home-done{ font:inherit; cursor:pointer; border-radius:999px;
  font-size:12.5px; font-weight:700; padding:7px 14px; min-height:32px }
.home-edit{ background:transparent; border:1px solid var(--line);
  color:var(--text-2) }
.home-edit:hover{ border-color:var(--ink); color:var(--ink) }
.home-edit em{ font-style:normal; color:var(--text-2); opacity:.7;
  margin-left:5px }
.home-done{ background:var(--ink); border:1px solid var(--ink); color:#fff }
.home-hint{ font-size:12.5px; color:var(--text-2); margin-right:auto }

.hcard.off{ opacity:.42 }
/* The tools bar carries the card's name, so the card's own heading would be
   the same word twice, six times down the page. */
.hcard.editing > .sys-sect > h2{ display:none }
.hcard.editing .s-note{ margin:0 }
.hcard-tools{ display:flex; align-items:center; gap:10px;
  margin:-6px -6px 12px; padding:0 0 10px;
  border-bottom:1px solid var(--line) }
.hcard-tools > b{ font-size:11px; font-weight:800; letter-spacing:.13em;
  text-transform:uppercase; color:var(--text-2); margin-right:auto;
  padding-left:6px }
.hcard-btns{ display:flex; align-items:center; gap:4px }
.hct{ width:30px; height:30px; border-radius:8px; cursor:pointer; font:inherit;
  font-size:14px; line-height:1; background:transparent; color:var(--text-2);
  border:1px solid transparent; display:flex; align-items:center;
  justify-content:center }
.hct:hover:not(:disabled){ background:var(--cream-2); color:var(--ink) }
.hct:disabled{ opacity:.25; cursor:default }

/* The same tick box as the sidebar switches, because it answers the same
   question and a second shape for one idea is a second thing to learn. */
.hct.tick{ border:1.5px solid var(--line-2); border-radius:7px;
  width:26px; height:26px; margin-left:4px }
.hct.tick.on{ background:var(--mint-d2); border-color:var(--mint-d2) }
.hct.tick.on::after{ content:''; width:5px; height:9px; margin-top:-2px;
  border:2px solid #fff; border-top:0; border-left:0;
  transform:rotate(43deg) }
.hct.tick:disabled{ opacity:.35 }

/* Cold hands, standing up, outside. Every one of these is a real target. §9 */
@media (pointer:coarse){
  .home-edit, .home-done{ min-height:var(--tap) }
  .hct{ width:var(--tap); height:var(--tap) }
  .hct.tick{ width:32px; height:32px; margin-left:6px }
}

.home .sys-sect{ gap:0 }
.home .sys-sect > h2{ font-size:11px; font-weight:800; letter-spacing:.13em;
  text-transform:uppercase; color:var(--text-2); line-height:14px;
  margin-bottom:10px }


/* ── NEEDS YOU ────────────────────────────────────────────────────────
   An orange rule down the side of each item, not a box around it. The bar is
   the same weight as the attention it is asking for, and three of them read
   as one list rather than three competing calls to action. */
.home-needs{ border-top:1px solid var(--line) }
.home-needs .need{ position:relative; padding:12px 0 13px 20px;
  border-left:3px solid var(--attn); border-bottom:1px solid var(--line) }
.home-needs .need:last-child{ border-bottom:0 }
/* The revealed rows live in their own wrapper, so a direct-child selector
   missed every one of them: no orange bar, no padding, a different shape of
   item appearing under the control. Descendant now. */
.home-rest .need:last-child{ border-bottom:0 }

/* the rest, one click away. A quiet row, not a button — pressing it reveals
   a list, it does not do anything to the business. */
.home-more{ display:block; width:100%; text-align:left; background:none;
  border:0; border-top:1px solid var(--line); padding:13px 0 0 22px;
  font:inherit; font-size:13px; font-weight:700; color:var(--text-2);
  cursor:pointer; min-height:var(--tap) }
.home-more:hover{ color:var(--ink) }
.home-more::after{ content:''; display:inline-block; width:6px; height:6px;
  margin:0 0 2px 9px; border-right:1.6px solid currentColor;
  border-bottom:1.6px solid currentColor; transform:rotate(45deg);
  vertical-align:middle }

.need .amt{ float:right; font-size:15.5px; font-weight:800;
  font-variant-numeric:tabular-nums; margin-left:18px; line-height:21px }
/* the money on the item that matters most is the one number on Home allowed
   to be a different colour — everything below it is ink */
.home-needs .need:first-child .amt{ color:var(--teal-d) }

.need h3{ font-size:16px; font-weight:800; letter-spacing:-.025em;
  line-height:21px }
/* The column can be any width; the sentence cannot. Past about 70 characters
   the eye loses the start of the next line, and Needs you is the one place on
   Home somebody actually reads rather than scans. */
.need p{ font-size:13px; color:var(--mid); margin-top:3px; line-height:18px;
  max-width:70ch }

/* beat 4 — what Noti already did. Quiet, and never looks like an action. */
.need .did{ font-size:12px; color:var(--text-2); font-weight:600;
  margin-top:5px; display:flex; align-items:flex-start; gap:7px;
  line-height:17px }
.need .did .dot{ margin-top:6px; width:6px; height:6px }

.need .go{ margin-top:7px; display:flex; gap:17px; align-items:center;
  flex-wrap:wrap }
.need .go button{ background:none; border:0; padding:0; cursor:pointer;
  font:inherit; font-size:13.5px; font-weight:700; color:var(--orange-btn);
  letter-spacing:-.01em }
.need .go button:hover{ text-decoration:underline; text-underline-offset:3px }
.need .go button.mute{ color:var(--text-2); font-weight:600 }


/* ── TODAY, and COMING UP ─────────────────────────────────────────────
   A day is a shape. The node is orange where something is live and hairline
   where it is not, so the shape of the day is readable before any word is. */
/* The spine. A day is a shape, and the shape needs a line to hang off —
   without it the nodes read as bullets and the timeline reads as a list. */
.home-time{ position:relative }
.home-time::before{ content:''; position:absolute; left:77.5px; top:14px;
  bottom:14px; width:1px; background:var(--line) }
.home-at{ display:flex; align-items:flex-start; padding:6px 0;
  position:relative; cursor:pointer; background:none; border:0; width:100%;
  text-align:left; font:inherit; color:inherit }
.home-at .w{ width:74px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; flex:none; font-size:12.5px; font-weight:600;
  color:var(--text-2); font-variant-numeric:tabular-nums; padding-top:2px }
/* quieter and smaller than the number it qualifies — it is a heading for the
   half of the day that follows, not part of the time */
.home-at .w em{ font-style:normal; font-size:10px; font-weight:700;
  letter-spacing:.04em; margin-left:3px; color:var(--faint) }
.home-at i{ width:7px; height:7px; border-radius:50%; background:var(--faint);
  flex:none; margin:6px 0 0; position:relative; z-index:1;
  box-shadow:0 0 0 3px var(--cream) }
.home-at.live i{ background:var(--orange) }
.home-at:hover i{ background:var(--faint) }
.home-at.live:hover i{ background:var(--orange) }
.home-at .m{ padding-left:17px; min-width:0; flex:1 }
.home-at .m b{ display:block; font-size:14px; font-weight:700;
  letter-spacing:-.015em }
.home-at .m span{ display:block; font-size:12.5px; color:var(--text-2);
  font-weight:500; margin-top:2px }


/* ── WATCHING ─────────────────────────────────────────────────────────
   Chips where there is no ratio; a bar ONLY where there is one. A progress
   bar over "6 quotes waiting" invents a measurement nobody took. */
.home-chips{ display:flex; flex-wrap:wrap; gap:7px }
.home-chip{ font-size:12.5px; font-weight:700; padding:7px 13px;
  border-radius:99px; background:var(--mint); color:var(--mint-d2);
  letter-spacing:-.01em }
.home-chip.warn{ background:var(--peach); color:var(--peach-d) }
.home-chip.wait{ background:var(--butter); color:var(--butter-d) }
.home-chip.none{ background:var(--line-2); color:var(--mid) }

.home-ratio{ margin-top:15px }
.home-ratio .h{ display:flex; justify-content:space-between; align-items:baseline;
  font-size:13px; font-weight:700; margin-bottom:7px }
.home-ratio .h span{ color:var(--text-2); font-weight:600; font-size:12.5px }
.home-bar{ height:7px; border-radius:99px; background:var(--line-2);
  overflow:hidden }
.home-bar i{ display:block; height:100%; border-radius:99px;
  background:var(--butter-d); transition:width .5s cubic-bezier(.2,.8,.2,1) }
.home-bar.is-ok i{ background:var(--mint-d2) }
.home-bar.is-tight i{ background:var(--butter-d) }
.home-bar.is-bad i{ background:var(--peach-d) }
.home-ratio small{ display:block; font-size:12.5px; color:var(--text-2);
  margin-top:9px; font-weight:500; line-height:18px }


/* ── NOTI DID ─────────────────────────────────────────────────────────
   The half nothing else in this market can show. A rule that acted is
   reassuring; a rule that DECIDED NOT TO is what makes it trustable, so the
   held-off ones are the reason this section exists. */
.home-trail{ display:flex; flex-direction:column; gap:1px }
.home-tr{ display:flex; gap:11px; align-items:flex-start; padding:4px 0 }
.home-tr .dot{ margin-top:6px; width:6px; height:6px }
.home-tr .m{ flex:1; min-width:0; font-size:13px; line-height:19px;
  color:var(--mid); font-weight:500 }
.home-tr .m b{ color:var(--ink); font-weight:700 }
.home-tr time{ font-size:12px; color:var(--faint); flex:none; font-weight:600;
  font-variant-numeric:tabular-nums; padding-top:2px }


/* ── THE CLOSING NOTE ─────────────────────────────────────────────────
   The one card on the page, and it is the last thing rather than the first.
   It exists so Home ends on Noti still being there rather than on a list
   running out. */
.home-note{ display:flex; align-items:center; gap:14px; width:100%;
  background:var(--white); border:0; border-radius:14px; padding:14px 16px;
  text-align:left; font:inherit; color:inherit; cursor:pointer;
  margin-top:4px; transition:box-shadow .16s }
.home-note:hover{ box-shadow:0 1px 3px rgba(26,22,19,.07) }
.home-note .dot{ width:9px; height:9px }
.home-note .m{ flex:1; min-width:0 }
.home-note .m b{ display:block; font-size:13.5px; font-weight:700;
  letter-spacing:-.015em }
.home-note .m span{ display:block; font-size:12.5px; color:var(--text-2);
  font-weight:500; margin-top:2px }
.home-note i{ width:7px; height:7px; flex:none;
  border-right:1.7px solid var(--faint); border-top:1.7px solid var(--faint);
  transform:rotate(45deg); margin-right:3px }

/* ── a quiet day, said like a person ──────────────────────────────────── */
.home-quiet{ font-size:13.5px; color:var(--text-2); font-weight:500;
  padding:2px 0; line-height:20px }


/* ═══════════════════════════════════════════════════════════════════════
   THE PHONE. §9 — a phone is not this page stacked.

   The information hierarchy is re-authored rather than collapsed:

     status → Needs you → Today → Watching → Noti did → Coming up

   Coming up goes LAST on a thumb. On a wide screen it sits in the right-hand
   column where the eye lands after the hero; on a phone it would push the
   proof that Noti is working below the fold, and next Tuesday is never more
   urgent than this morning.

   One DOM, in the phone's order. display:contents dissolves the two desktop
   columns so every section becomes a direct flex item, and `order` does the
   rest — no second markup path, so the two layouts can never drift.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width:699px){
  .home{ display:flex; flex-direction:column; gap:30px }
  .home-main, .home-side{ display:contents }
  /* The order used to be pinned to the six section names. It moved onto the
     card because the order is no longer a constant — the person choosing it
     is, and their one list IS the phone's sequence. The shipped arrangement
     still produces exactly the re-authored order, because that is the order
     the card list is written in. */
  .hcard{ order:var(--o, 0) }
}

@media (max-width:699px){
  .home-hero{ padding:18px 18px 17px; border-radius:14px }
  .home-said{ font-size:23px; line-height:29px; gap:11px; margin-top:7px }
  .home-said .dot{ width:9px; height:9px }
  .home-sub{ font-size:13.5px; margin-top:5px }
  /* the creed is a desktop luxury: on a phone it competes with the status */
  .home-creed{ display:none }

  .home-orbit{ gap:8px; margin-top:14px; padding-top:13px;
    border-top:1px solid rgba(255,255,255,.13) }
  /* one LINE of facts, not a 2x2 grid of tiles — a cramped mini-dashboard is
     the thing this design argues against */
  .home-orbit .lnk{ display:none }
  .home-orbit .n{ flex-direction:row; align-items:baseline; gap:5px }
  .home-orbit .n b{ font-size:14px; line-height:19px }
  .home-orbit .n span{ font-size:11.5px; letter-spacing:0; text-transform:none;
    font-weight:600 }
  .home-orbit .n:not(:last-child)::after{ content:'\00b7'; margin-left:8px;
    color:rgba(255,255,255,.35) }

  .home{ gap:26px; margin-top:20px }

  /* ── NEEDS YOU, re-authored. Not every item at equal weight. ──────────
     The first keeps the full treatment and two real thumb targets. Everything
     after becomes a row: title, one line of why, the money, a chevron. Three
     equal blocks on a 375px screen is three things shouting at the same
     volume, which is the same as none of them shouting. */
  .home-needs .need:first-child .go{ gap:9px; margin-top:14px }
  .home-needs .need:first-child .go button.b1,
  .home-needs .need:first-child .go button.b2{
    border-radius:99px; padding:0 18px; min-height:44px; font-size:13.5px;
    font-weight:800 }
  .home-needs .need:first-child .go button.b1{
    background:var(--orange-btn); color:#fff }
  .home-needs .need:first-child .go button.b1:hover{ text-decoration:none }
  .home-needs .need:first-child .go button.b2{
    background:var(--white); color:var(--ink) }
  .home-needs .need:first-child .go button.b2:hover{ text-decoration:none }
  .home-needs .need:first-child .go button.mute{ margin-left:auto;
    min-height:var(--tap); padding:0 4px }

  .home-needs .need:not(:first-child){
    padding:11px 26px 11px 16px; min-height:var(--tap);
    border-left-color:var(--line) }
  .home-needs .need:not(:first-child) h3{ font-size:14.5px; line-height:20px;
    font-weight:700; padding-right:8px }
  .home-needs .need:not(:first-child) p{ font-size:12.5px; margin-top:2px;
    color:var(--text-2); line-height:17px;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
  .home-needs .need:not(:first-child) .amt{ font-size:14px; margin-left:10px }
  /* the reassurance and the buttons are the first item's privilege */
  .home-needs .need:not(:first-child) .did,
  .home-needs .need:not(:first-child) .go{ display:none }
  .home-needs .need:not(:first-child) .need-hit{
    display:block; position:absolute; inset:0; background:none; border:0;
    padding:0; cursor:pointer; -webkit-tap-highlight-color:transparent }
  .home-needs .need:not(:first-child) .need-hit:active{
    background:rgba(26,22,19,.035) }
  .home-needs .need:not(:first-child) .need-ch{
    display:block; position:absolute; right:2px; top:50%; width:7px; height:7px;
    margin-top:-4px; border-right:1.7px solid var(--faint);
    border-top:1.7px solid var(--faint); transform:rotate(45deg) }

  /* thumbs, everywhere else on this screen */
  .home-at{ min-height:var(--tap) }
  .home-at .w{ width:52px }
}

/* off on a wide screen: the row is not a target, the buttons are */
.need-hit{ display:none }
.need .need-ch{ display:none }


/* ═══════════════════════════════════════════════════════════════════════
   ARCADE — ported from _design/home-arcade.html, unchanged in substance.

   THE RULE, locked 16 September 2026 (PRODUCT-UI §0c): the `noti●` wordmark
   is the door. Not the hero, not a menu item. The mark is on every screen, so
   the clue can find somebody in Money or Stock & Supply — an Arcade you can
   only reach from Home is an Arcade nobody reaches.

     the logo is where Noti becomes playful
     the hero is where Noti becomes expressive

   Discovery is on the mark; the STAGE is the dark hero when you are on Home,
   because the rectangle is already there and growing it reads as the product
   opening up rather than a page you navigated to. One surface, three sizes:
   status → Arcade → the game. Leaving is the box getting smaller.

   cream UI → dark cabinet → atmospheric surround → crisp playfield.
   ═══════════════════════════════════════════════════════════════════════ */
.logo{position:relative}
.logo i{width:6px;height:6px;border-radius:50%;background:var(--orange);
  transition:opacity .2s, transform .3s}
.logo i.gone{opacity:0;transform:scale(.4)}

/* ── the logo IS the clue ───────────────────────────────────────────────
   Straight off the Arcade board: n. → the dot moves → the snake forms →
   play. The monthly animation happens on the WORDMARK, which is why it works
   as brand rather than as an animation playing somewhere in the product —
   and the thing that forms is made of the dot that was already there.

   It then travels into the hero, because that is where it has room. Two dark
   Noti surfaces, one object moving between them. */
.lclue{position:absolute;left:0;top:-6px;width:160px;height:34px;
  pointer-events:none}
/* ── a snake, not five squares ──────────────────────────────────────────
   The board ends on an actual creature: a head with eyes, a body that grew,
   sitting in the mark. "The dot moves" is beat two of four, not the whole
   animation — so the head is bigger, rounded on the leading edge, and has a
   face. Without the eyes it is a queue of rectangles.

   No entrance animation on any of these. `arrive` has fill-mode backwards and
   fought the per-frame JS: the keyframe's from-state won and everything
   computed to opacity 0 while the inline style said 1. */
/* Sized against the WORDMARK, not against the dot. On the board the snake is
   about as tall as the `n` — at dot-size it reads as a green smudge beside
   the logo rather than a creature in it. The mark is 18px, so the body is 10
   and the head 13. */
/* SNAKE on the mark. Square cells on a grid, because the thing in the cabinet
   is the game and not the animal: a segment is a cell, it is the same size as
   every other cell, and it never sits between two of them.

   The eyes and the rotation are gone with the sine wave that needed them — a
   square that steps north then east does not have a face pointing anywhere. */
.lseg{position:absolute;width:7px;height:7px;border-radius:1.5px;
  background:#6FD99A;box-shadow:0 0 5px rgba(111,217,154,.35)}
.lhead{position:absolute;width:7px;height:7px;border-radius:2px;
  background:#C9F5D8;box-shadow:0 0 9px rgba(201,245,216,.6)}
/* The food is the dot it came from, small and orange, sitting on the board
   waiting to be eaten. */
.lpip{position:absolute;width:5px;height:5px;margin:1px;border-radius:50%;
  background:var(--orange,#4B3CA8);box-shadow:0 0 6px rgba(75,60,168,.6);
  transition:opacity .2s}
.ltongue{position:absolute;width:6px;height:2px;background:#FF5C7A;
  border-radius:1px;opacity:0;box-shadow:0 0 4px rgba(255,92,122,.6)}
/* ── the other months, each with its own world ──────────────────────────
   Same four beats as Snake, same rule: the DOT becomes the playable thing,
   and by beat four there is a game happening on the mark rather than one
   shape travelling across it. Sized against the wordmark throughout. */

/* Breakout — the dot is the ball, and there are bricks to break */
.lball{position:absolute;width:8px;height:8px;border-radius:50%;
  background:#F5A3D0;box-shadow:0 0 9px rgba(245,163,208,.55)}
.lbrick{position:absolute;width:12px;height:5px;border-radius:2px;
  background:#E86BB0;box-shadow:0 0 6px rgba(232,107,176,.35);
  transition:opacity .18s, transform .18s}
.lpad{position:absolute;width:19px;height:3.5px;border-radius:2px;
  background:#F5A3D0;box-shadow:0 0 8px rgba(245,163,208,.5)}

/* Space — the dot is the ship, and something is shooting back */
.lship{position:absolute;width:0;height:0;border-left:7px solid transparent;
  border-right:7px solid transparent;border-bottom:15px solid #7FE3F0;
  filter:drop-shadow(0 0 7px rgba(127,227,240,.6))}
.lshot{position:absolute;width:2px;height:8px;border-radius:1px;
  background:#BFF4FB;box-shadow:0 0 6px rgba(191,244,251,.8)}
.lalien{position:absolute;width:14px;height:11px;border-radius:6px 6px 3px 3px;
  background:#4FD0E0;box-shadow:0 0 9px rgba(79,208,224,.5)}
.lalien::after{content:'';position:absolute;left:3px;top:3.5px;width:2.2px;
  height:2.2px;border-radius:50%;background:#062329;box-shadow:0 0 0 #062329,
  5.5px 0 0 #062329}

/* Runner — the dot is the runner, and there is ground and a cactus */
.lrun{position:absolute;width:8px;height:12px;border-radius:2px 2px 1px 1px;
  background:#F2C14E;box-shadow:0 0 7px rgba(242,193,78,.5)}
.lrun::after{content:'';position:absolute;left:1px;bottom:-3px;width:2.5px;
  height:3px;background:#F2C14E;border-radius:1px;box-shadow:4px 0 0 #F2C14E}
.lground{position:absolute;height:1.5px;background:rgba(242,193,78,.45);
  border-radius:1px}
.lcactus{position:absolute;width:5px;height:11px;border-radius:2px;
  background:#5FBF7A;box-shadow:0 0 6px rgba(95,191,122,.4)}
.lcactus::after{content:'';position:absolute;left:-3px;top:3px;width:3px;
  height:5px;border-radius:2px;background:#5FBF7A}

/* Falling blocks — the dot is the piece, and a stack builds */
.lblk{position:absolute;width:10px;height:10px;border-radius:2px;
  background:#9F8CF5;box-shadow:0 0 8px rgba(159,140,245,.5)}
.lstack{position:absolute;width:10px;height:10px;border-radius:2px;
  transition:opacity .2s}
.lflash{position:absolute;height:10px;border-radius:3px;background:#fff;
  opacity:0;box-shadow:0 0 16px rgba(255,255,255,.9)}

/* ── the remaining seven ────────────────────────────────────────────── */

/* Flappy — the dot sprouts a wing and a beak but STAYS ROUND */
.lbird{position:absolute;width:11px;height:11px;border-radius:50%;
  background:#6FD3F5;box-shadow:0 0 9px rgba(111,211,245,.55)}
.lbird::before{content:'';position:absolute;right:-3.5px;top:4px;width:0;height:0;
  border-top:2.5px solid transparent;border-bottom:2.5px solid transparent;
  border-left:4px solid #FFB020}
.lbird::after{content:'';position:absolute;left:1.5px;top:5px;width:6px;
  height:3.5px;border-radius:2px;background:rgba(255,255,255,.75);
  transform-origin:80% 50%}
.lpipe{position:absolute;width:9px;background:#36A8CC;border-radius:2px;
  box-shadow:0 0 7px rgba(54,168,204,.4)}

/* 2048 — tiles live AROUND the mark rather than replacing it */
.ltile{position:absolute;min-width:15px;height:15px;border-radius:3px;
  display:flex;align-items:center;justify-content:center;font-size:9px;
  font-weight:800;color:#fff;background:#7C5CE0;
  box-shadow:0 0 8px rgba(124,92,224,.45);padding:0 2px}

/* Memory — cards that flip, and get it wrong first */
.lcard{position:absolute;width:13px;height:17px;border-radius:3px;
  background:#2A1522;border:1.5px solid #F472B6;box-shadow:0 0 7px rgba(244,114,182,.35);
  display:flex;align-items:center;justify-content:center;font-size:8px;
  font-weight:800;color:#F472B6;transition:transform .16s}
.lstar{position:absolute;width:4px;height:4px;background:#F9A8D4;
  border-radius:1px;transform:rotate(45deg);box-shadow:0 0 6px rgba(249,168,212,.8)}

/* Noti Dash — the word itself is the course */
.ldash{position:absolute;width:10px;height:10px;border-radius:50%;
  background:#4DA3FF;box-shadow:0 0 9px rgba(77,163,255,.6)}
.ldash::after{content:'';position:absolute;left:2px;top:9px;width:6px;height:7px;
  border-radius:2px;background:#4DA3FF}
.lhazard{position:absolute;width:0;height:0;border-left:5px solid transparent;
  border-right:5px solid transparent;border-bottom:9px solid #FF6B6B;
  filter:drop-shadow(0 0 5px rgba(255,107,107,.5))}
.ltick{position:absolute;width:11px;height:11px;border-radius:50%;
  background:rgba(94,234,212,.2);box-shadow:0 0 9px rgba(94,234,212,.6);
  display:flex;align-items:center;justify-content:center;font-size:8px;
  font-weight:900;color:#5EEAD4}

/* Reaction — stillness, then red */
.lring{position:absolute;border-radius:50%;border:2px solid #FF4D5E;opacity:0}
.ltime{position:absolute;font-size:9px;font-weight:800;color:#FF7A88;
  letter-spacing:.02em;opacity:0}

/* Stack — rainbow, and it wobbles */
.lblock{position:absolute;height:6px;border-radius:2px;
  box-shadow:0 0 6px rgba(94,234,212,.3)}

/* Championship — gold, particles, a crown that is too big */
.lcrown{position:absolute;width:13px;height:9px;
  background:linear-gradient(#FFE27A,#FFB020);
  clip-path:polygon(0 100%,100% 100%,100% 28%,78% 52%,50% 4%,22% 52%,0 28%);
  filter:drop-shadow(0 0 7px rgba(255,201,74,.7))}
.lspark{position:absolute;width:3px;height:3px;border-radius:50%;
  background:#FFE27A;box-shadow:0 0 6px rgba(255,226,122,.9)}

.lseg,.lpip,.lball,.lship,.lrun,.lblk,.lbrick,.lstack,.lalien,.lbird,.ltile,
.lcard,.ldash,.lblock,.lcrown{transition:opacity .25s}

/* The door, and it is open at all times — during the clue, during the long
   rest between clues, and under reduced motion where the clue never plays.
   Generous on purpose: the wordmark is 25px of text and a hit box that only
   covers the glyphs is a door most people never find they can push. */
.lhit{position:absolute;left:-10px;top:-12px;width:170px;height:70px;border:0;
  background:none;cursor:pointer;pointer-events:auto;padding:0;z-index:5}

/* ── the caption ──────────────────────────────────────────────────────
   The smallest type in the product, sitting in the space the wordmark
   already reserved below itself. Quiet enough to ignore on the four
   hundredth visit, present enough to be read on the first — which is the
   only job it has. It picks up the month's colour so the label and the
   thing animating above it are visibly the same object. */
/* Below the playfield, not under it. Measured over a full cycle the clue runs
   from 8px to 40px down the mark, so the caption starts at 46 and the band is
   clipped at 42 — a label the animation keeps painting over is worse than no
   label at all, and "nearly clear" is the version that looks like a bug on
   one frame in twenty. */
.logo{ padding-bottom:44px }
.lclue{ height:48px; overflow:hidden }
.logo .lcap{ position:absolute; left:12px; top:46px; z-index:4;
  font-size:9px; font-weight:800; letter-spacing:.17em; text-transform:uppercase;
  color:rgba(255,255,255,.34); white-space:nowrap; pointer-events:none;
  opacity:0; transform:translateY(-2px);
  transition:opacity .3s, transform .3s, color .2s }
/* only while the mark is a game. It fades with the animation rather than
   switching, so the rail never flickers a label on and off. */
.logo.lplay .lcap{ opacity:1; transform:none }
/* NOT an <i>: noti.css styles `.logo i` as the 6px orange dot, display:block,
   which turned the separator into a square and broke the caption onto two
   lines. */
.logo .lcap .sep{ color:var(--gc, var(--orange)); opacity:.8; margin:0 2px }
.logo:hover .lcap{ color:var(--gc, #fff) }
.lhit:focus-visible{outline:2.5px solid #9BE8B4;outline-offset:3px;
  border-radius:8px}
.rail a{display:flex;align-items:center;gap:11px;padding:9px 10px;
  border-radius:10px;color:rgba(255,255,255,.6);font-size:13px;font-weight:600}
.rail a.on{background:rgba(255,255,255,.1);color:#fff}
.rail svg{width:16px;height:16px;flex:none;stroke:currentColor;fill:none;
  stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.stage{flex:1;min-width:0;padding:22px 30px 34px}


.ark-seg,.ark-ball,.ark-ship,.ark-run,.ark-blk{animation:arrive .32s ease-out backwards}

/* the normal contents, which fade out when Arcade opens */
.ark-biz{transition:opacity .22s}
.home-hero.ark-open .ark-biz{opacity:0;pointer-events:none}
.home-hero.ark-open::after{opacity:.55}


/* ═══ THE CLUE ══════════════════════════════════════════════════════════
   A few pixels moving inside the dark surface. Small enough to be missed if
   you are working, big enough to be seen if you are not. It is a BUTTON, so
   it is keyboard reachable and announces itself — an Easter egg that only
   exists for a mouse is an Easter egg half the people using Noti can never
   find. */
.ark-clue{position:absolute;inset:0;pointer-events:none;z-index:2}
.ark-seg{position:absolute;width:9px;height:9px;border-radius:2px;
  background:#9BE8B4;box-shadow:0 0 8px rgba(155,232,180,.35)}
.ark-seg.head{border-radius:3px;background:#C9F5D8}
.ark-hit{position:absolute;width:30px;height:30px;margin:-10px 0 0 -10px;
  border-radius:50%;border:0;background:none;cursor:pointer;pointer-events:auto;
  padding:0}
.ark-hit:focus-visible{outline:2.5px solid #9BE8B4;outline-offset:2px}

/* other months, same system */
.ark-ball{position:absolute;width:9px;height:9px;border-radius:50%;background:#F5A3D0;
  box-shadow:0 0 9px rgba(245,163,208,.45)}
.ark-ship{position:absolute;width:0;height:0;border-left:6px solid transparent;
  border-right:6px solid transparent;border-bottom:13px solid #7FE3F0;
  filter:drop-shadow(0 0 6px rgba(127,227,240,.5))}
.ark-run{position:absolute;width:8px;height:12px;border-radius:2px;background:#F2C14E;
  box-shadow:0 0 8px rgba(242,193,78,.4)}
.ark-blk{position:absolute;width:11px;height:11px;border-radius:2px;background:#9F8CF5;
  box-shadow:0 0 9px rgba(159,140,245,.45)}

/* ═══ ARCADE — it GROWS out of the hero ════════════════════════════════ */
.ark-panel{position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:4px;opacity:0;
  pointer-events:none;transition:opacity .3s .16s;z-index:3;text-align:center}
.home-hero.ark-open .ark-panel{opacity:1;pointer-events:auto}
.ark-panel .brand{display:flex;align-items:baseline;gap:9px;margin-bottom:4px}
.ark-panel .brand b{font-size:19px;font-weight:800;letter-spacing:-.03em;color:#fff;
  display:flex;align-items:baseline;gap:4px}
.ark-panel .brand b i{width:6px;height:6px;border-radius:50%;background:var(--orange)}
.ark-panel .brand span{font-size:12px;font-weight:700;letter-spacing:.34em;
  text-transform:uppercase;color:rgba(255,255,255,.55)}
.ark-panel h3{font-size:42px;font-weight:800;letter-spacing:.14em;margin:10px 0 2px;
  color:#9BE8B4;text-shadow:0 0 26px rgba(155,232,180,.35)}
/* Everything in Arcade arrives on a stagger, so the panel assembles rather
   than switching on. 60ms apart is enough to read as sequence. */
.home-hero.ark-open .ark-panel > *{animation:rise .34s cubic-bezier(.2,.9,.3,1) backwards}
.home-hero.ark-open .ark-panel > *:nth-child(2){animation-delay:.06s}
.home-hero.ark-open .ark-panel > *:nth-child(3){animation-delay:.12s}
.home-hero.ark-open .ark-panel > *:nth-child(4){animation-delay:.18s}
.home-hero.ark-open .ark-panel > *:nth-child(5){animation-delay:.24s}
.home-hero.ark-open .ark-panel > *:nth-child(6){animation-delay:.30s}
@keyframes rise{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}

/* eating pops the score, and the board shakes when it ends */
@keyframes pop{0%{transform:scale(1)}40%{transform:scale(1.35)}100%{transform:scale(1)}}
.ark-hud b.pop{animation:pop .28s ease-out; display:inline-block}
@keyframes shake{10%,90%{transform:translateX(-2px)}20%,80%{transform:translateX(3px)}
  30%,50%,70%{transform:translateX(-5px)}40%,60%{transform:translateX(5px)}}
.ark-board.shake{animation:shake .4s}
.ark-panel .tl{font-size:13px;color:rgba(255,255,255,.55);font-weight:600}
.ark-panel .play{margin-top:20px;background:#9BE8B4;color:#0B1410;border:0;
  border-radius:99px;padding:13px 34px;font:inherit;font-size:15px;
  font-weight:800;letter-spacing:.06em;cursor:pointer}
.ark-panel .hs{margin-top:16px;font-size:12.5px;color:rgba(255,255,255,.45);
  font-weight:600}
.ark-panel .hs b{color:#fff;font-variant-numeric:tabular-nums}
/* ── PLAY. The same rectangle grows again. ─────────────────────────────
   Three sizes of one surface: status → Arcade → the game. Never a page, so
   there is nothing to navigate back FROM — leaving is the box getting smaller
   again, which is why it feels like part of Noti rather than a detour. */
.home-hero.ark-playing{ }
.ark-play{position:absolute;inset:0;display:none;flex-direction:column;
  align-items:center;justify-content:center;gap:14px;z-index:4}

/* ══ THE SURROUND ══════════════════════════════════════════════════════
   The black around the playfield was reading as a frame. It is now the
   atmosphere layer: the game's world continuing past the edge of the screen,
   with pieces deliberately breaking out of the boundary.

   cream UI → dark cabinet → atmospheric surround → crisp playfield

   THE RULE: the surround is never wallpaper. Every element either comes from
   this game's world, implies a previous game happened there, or reacts to
   something inside the playfield. Nothing is there to fill space.

     · clearest where it meets the playfield, dissolving into the machine at
       the corners — an even wash reads as decoration
     · it REACTS: eating sends ripples out from the board, a brick throws real
       fragments that fall through the black under gravity, an impact blooms
       behind that part of the cabinet, a cleared board flashes the whole thing
     · it REMEMBERS: scorch marks where food was eaten, a loose brick that
       never made it back, a ghost trajectory from a previous ball
   ══════════════════════════════════════════════════════════════════════ */
.ark-surround{position:absolute;inset:0;pointer-events:none;z-index:0;
  border-radius:18px}
.ark-play .ark-hud, .ark-play .ark-board{position:relative;z-index:1}
.home-hero.ark-playing .ark-play{display:flex}
.home-hero.ark-playing .ark-panel{opacity:0;pointer-events:none}
/* ══ THE CABINET ═══════════════════════════════════════════════════════
   Page → cabinet → glowing little world. Three surfaces, not one black box.

   The flat version failed because everything sat at the same depth: the
   playfield, the shell and the page behind were all "dark", so the game had
   nowhere to live and the snake looked like it was hiding rather than lit up.

   Each game tints its own world through --g (accent) and --gbg (world),
   set in JS when Arcade opens. */
.home-hero.ark-playing{ background:#12100f }

.ark-board{
  /* The CSS size, stated. Without it the canvas lays out at its BUFFER size,
     and the buffer is now the device's — so raising it for sharpness doubled
     the board on a retina screen. The buffer is resolution; this is size. */
  width:560px; height:320px;
  border-radius:14px;
  /* the world: lighter than the shell, and tinted by the game */
  background:
    /* somewhere for the action to live */
    radial-gradient(120% 90% at 50% 45%,
      color-mix(in srgb, var(--g,#7BFF9E) 9%, transparent), transparent 70%),
    /* barely-there grid — an arcade display, not graph paper */
    repeating-linear-gradient(0deg, rgba(255,255,255,.028) 0 1px, transparent 1px 20px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.028) 0 1px, transparent 1px 20px),
    var(--gbg,#171b18);
  /* the edge glows in the game's colour, so the cabinet knows what is in it */
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--g,#7BFF9E) 22%, transparent),
    inset 0 0 26px color-mix(in srgb, var(--g,#7BFF9E) 9%, transparent),
    0 0 34px -8px color-mix(in srgb, var(--g,#7BFF9E) 32%, transparent);
}

/* A deliberate header: score left, best beside it, controls right. */
.ark-hud{ display:flex; align-items:baseline; gap:14px; width:560px; max-width:100%;
  padding:0 2px }
.ark-hud .sp{ margin-left:auto }
.ark-hud b{ color:#fff; font-variant-numeric:tabular-nums; font-size:15px }
.ark-hud .k{ font-size:11px; color:rgba(255,255,255,.34); font-weight:600;
  letter-spacing:.04em }

/* ── game over, as a card in the cabinet ─────────────────────────────── */
.ark-over{position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;background:rgba(8,7,6,.55);border-radius:18px;z-index:5}
.ark-over .ark-card{background:rgba(23,27,24,.96);border-radius:14px;
  padding:22px 30px;display:flex;flex-direction:column;align-items:center;
  gap:9px;
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--g,#7BFF9E) 26%, transparent),
             0 0 40px -6px color-mix(in srgb, var(--g,#7BFF9E) 34%, transparent)}
.ark-over .ark-card h4{font-size:30px;font-weight:800;letter-spacing:-.02em;color:#fff;
  font-variant-numeric:tabular-nums}
.ark-over .ark-card p{font-size:13px;color:rgba(255,255,255,.58);font-weight:600}
.ark-over .ark-card .again{margin-top:6px;background:var(--g,#7BFF9E);color:#07130C;border:0;
  border-radius:99px;padding:11px 28px;font:inherit;font-size:14px;
  font-weight:800;cursor:pointer;
  box-shadow:0 0 22px -4px color-mix(in srgb, var(--g,#7BFF9E) 70%, transparent)}



.ark-panel .back{position:absolute;top:16px;left:18px;background:none;border:0;
  color:rgba(255,255,255,.5);font:inherit;font-size:12.5px;font-weight:700;
  cursor:pointer;display:flex;align-items:center;gap:6px}
.ark-panel .back:hover{color:#fff}



/* ═══════════════════════════════════════════════════════════════════════
   THE SHELL — the rail and the top bar, to the approved screen.

   These override noti.css rather than replacing it, because the rail is also
   the pre-pivot product's rail and Custom builds still render against it.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── where you are ────────────────────────────────────────────────────
   A solid orange bar reads as a button somebody pressed. Where you ARE is
   not an action — it is a fact, and the fact is quieter than the thing you
   might do next. So: a light surface, the icon in brand orange, and a short
   orange mark on the leading edge doing the actual pointing. */
.rail .ri.on{ background:rgba(255,255,255,.95); color:var(--ink);
  font-weight:700; position:relative }
.rail .ri.on svg{ color:var(--orange) }
.rail .ri.on::before{ content:''; position:absolute; left:0; top:50%;
  width:3px; height:19px; margin-top:-9.5px; border-radius:0 3px 3px 0;
  background:var(--orange) }
.rail .ri.on .bd{ background:var(--attn); color:#fff }

/* A section's own one-line summary, where it has one. Sits directly under
   the page header rather than under a second title of its own. */
.sect-sub{ margin:0 0 14px }

/* ── what is inside the area you are in ───────────────────────────────
   Only the open area shows its sections. Invoices used to be two clicks deep
   and invisible from the rail — you had to know it was a tab on Money to
   find it.

   Deliberately quieter than an area: smaller, no icon, indented to the width
   of one so the labels start where the area labels start rather than under
   their icons. It is a list of what is in there, not a second rail. */
.rail .risubs{ display:flex; flex-direction:column; gap:1px;
  margin:2px 0 6px; padding-left:15px;
  border-left:1px solid rgba(255,255,255,.10); margin-left:19px }
.rail .risub{ appearance:none; border:0; background:transparent;
  font:inherit; font-size:13px; font-weight:600; color:#8C8279;
  text-align:left; padding:6px 10px; border-radius:8px; cursor:pointer;
  transition:color .12s, background .12s }
.rail .risub:hover{ color:#fff; background:rgba(255,255,255,.06) }
/* The section you are on. A dot rather than a fill: the area above already
   carries the light surface saying where you are, and two of those in a row
   is two answers to one question. */
.rail .risub.on{ color:#fff; font-weight:700; position:relative }
.rail .risub.on::before{ content:''; position:absolute; left:-18px; top:50%;
  width:5px; height:5px; margin-top:-2.5px; border-radius:50%;
  background:var(--orange) }
/* Something in that section is not set. Said here rather than only once
   somebody has opened Settings and can see the list anyway. */
.rail .risub{ display:flex; align-items:center; gap:7px }
.rail .risub-dot{ width:5px; height:5px; border-radius:50%;
  background:var(--attn); flex:none }

/* ── the rail ends on Noti still being there ──────────────────────────
   Pinned to the bottom, so the nav keeps its own length and the card does not
   drift up under a short list of modules. */
.rail .railfoot{ margin-top:auto }
.rail .railfoot .tip{ background:rgba(255,255,255,.055); border-radius:15px;
  padding:11px 7px 8px }
.rail .railfoot .tip .w{ display:flex; align-items:flex-start; gap:9px;
  color:#fff; font-size:12.5px; font-weight:700; line-height:17px;
  letter-spacing:-.01em; padding:0 5px 10px;
  border-bottom:1px solid rgba(255,255,255,.07) }
.rail .railfoot .tip .w .dot{ margin-top:5px }

/* ── the bell ─────────────────────────────────────────────────────────
   The badge is the same count the hero says. It is not drawn at all at zero:
   a bell wearing a 0 is a product telling you it has nothing to tell you. */
.top .bell{ position:relative }
.top .bell .bd{ position:absolute; top:5px; right:5px; min-width:8px;
  height:8px; border-radius:99px; background:var(--orange);
  box-shadow:0 0 0 2.5px var(--cream) }
.top .bell .bd.many{ min-width:17px; height:17px; top:1px; right:1px;
  color:#fff; font-size:10.5px; font-weight:800; display:flex;
  align-items:center; justify-content:center; padding:0 4px }

/* ── the top bar is one group on the right ────────────────────────────
   The page owns the left edge; the shell owns the right. A search field
   floating alone at top-left competes with the hero for the first look, and
   the hero has to win that. */
.top .sp{ flex:1 }
.top .search{ flex:0 1 420px; max-width:420px }
.top .who{ display:flex; align-items:center; gap:10px; background:var(--white);
  border-radius:99px; padding:6px 14px 6px 6px }
.top .who svg{ width:16px; height:16px; color:var(--faint); flex:none;
  stroke:currentColor; fill:none; stroke-width:2; transform:rotate(90deg) }


/* ── the rail carries the shell ───────────────────────────────────────
   A header band across the top costs 120px of every screen forever. On Home,
   whose whole job is to be taken in without scrolling, that was the
   difference between fitting and not — so search, the account and the
   attention count all moved into the rail, and the page starts at the top of
   the window. */
.app > .body > .top{ display:none }

/* With no header band, the pane's own top padding is the only thing left
   holding it below the rail — 24px of nothing that reads as the content
   having slipped down the page. Every pane starts level with the top of the
   rail instead, which is what makes the two columns read as one object. */
@media (min-width:700px){
  .app > .body > .page > .sys-page{ padding-top:0 }
}
@media (max-width:699px){
  /* The strip is the wordmark and nothing else, on the same near-black the
     rail uses — so the mark is on the surface .logo was written for and the
     top of a phone screen is a Noti surface rather than a search field. */
  .app > .body > .top{ display:flex; align-items:center;
    background:var(--ink); border-radius:14px; padding:11px 4px 11px 6px }
  .top .mlogo{ padding:0 8px; flex:none; position:relative }
  .top .top-area{ flex:1; min-width:0; padding:0 10px 0 12px; margin-left:2px;
    border-left:1px solid rgba(255,255,255,.14); color:#fff; font-size:15px; font-weight:700;
    letter-spacing:-.01em; line-height:20px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
  .top .top-area:empty{ display:none }
  #pane h1.same-as-bar{ display:none }
  .top .mlogo b{ font-size:20px }
  .top .mlogo .lclue{ left:-2px; top:-8px }
  .top .mlogo .lcap{ display:none }

  /* The caption is positioned for the rail, where there is a column ofempty
     space under the mark. Inside the hero it lands on the eyebrow. There is
     no room for it on a phone either way — the mark is the invitation. */
  .home-mark .lcap{ display:none }

  /* On Home the hero is already that surface, so the strip would be a second
     black bar stacked on the first. The hero carries the mark instead. */
  .app.pane-home > .body > .top{ display:none }
  .home-mark{ padding:0 0 12px; position:relative; z-index:2 }
  .home-mark b{ font-size:20px }
  .home-hero.stuck .home-mark{ display:none }

}
/* Summoned, not permanent, wherever the rail cannot hold the field (a phone,
   or a tablet's icon rail): search is something you ask for. */
@media (max-width:1099px){
  .app > #search{ display:none }
  .app.searching > #search{ display:block; position:fixed; z-index:120;
    left:10px; right:10px; top:10px; max-width:640px; margin-inline:auto }
  .app.searching > #search input{ font-size:16px; padding:15px 16px 15px 44px;
    box-shadow:0 18px 40px -16px rgba(26,22,19,.45) }
  .app.searching > #search svg{ left:17px; width:18px; height:18px }
  .app.searching > #search kbd{ display:none }
  .app.searching > #search .results{ left:0; right:0; width:auto }
}
/* the mark belongs to the rail wherever there is one */
@media (min-width:700px){ .home-mark{ display:none } }

/* ── the tablet rail: icons with their words (LAYOUT.md) ──────────────── */
.rail .rsearch{ display:none }
@media (min-width:700px) and (max-width:1099px){
  .rail .logo{ justify-content:center; padding:0 0 14px }
  .rail .logo b{ font-size:21px }
  .rail .logo .lcap{ display:none }
  .rail .railslot{ display:none }
  .rail .rsearch{ display:flex; margin-bottom:6px }
  .rail .ri{ flex-direction:column; justify-content:center; gap:4px; min-height:58px;
    padding:8px 2px 7px; font-size:10.5px; font-weight:700; text-align:center; position:relative }
  .rail .ri span{ max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; line-height:1.2 }
  .rail .ri span[data-short]{ font-size:0 }
  .rail .ri span[data-short]::after{ content:attr(data-short); font-size:10.5px }
  .rail .ri svg{ width:20px; height:20px }
  .rail .ri .bd{ position:absolute; top:4px; right:12px; margin:0; min-width:17px; height:17px; font-size:10px }
  .rail .ri.on::before{ left:-8px }
  .rail .risubs{ display:none }
  .rail .railfoot .tip{ padding:8px 4px; background:none }
  .rail .railfoot .tip .w, .rail .railfoot .nm{ display:none }
  .app .rail .railme{ flex-direction:column; gap:8px; align-items:center; padding:0; border:0; margin-top:0 }
}

/* ── the section strip: an area's sections under the thumb ────────────── */
.secstrip{ display:none }
@media (max-width:1099px){
  .secstrip:not([hidden]){ display:flex; gap:6px; overflow-x:auto; overscroll-behavior-x:contain;
    scrollbar-width:none; padding:2px 2px 4px; margin:0 -2px; scroll-padding-inline:12px }
  .secstrip::-webkit-scrollbar{ display:none }
  .secchip{ flex:none; display:inline-flex; align-items:center; gap:6px; min-height:var(--tap);
    padding:0 16px; border-radius:99px; border:1.5px solid var(--line); background:var(--white);
    color:var(--text-2); font:inherit; font-size:13.5px; font-weight:700; white-space:nowrap; cursor:pointer }
  .secchip.on{ background:var(--ink); border-color:var(--ink); color:#fff }
}

.rail .railslot{ padding:0 3px 14px }
.rail .search{ max-width:none; flex:none }
.rail .search input{ background:rgba(255,255,255,.07); color:#fff;
  border:1.5px solid transparent; padding:10px 12px 10px 36px; font-size:13px;
  border-radius:12px }
.rail .search input::placeholder{ color:#8C8279 }
.rail .search input:focus{ background:rgba(255,255,255,.12);
  border-color:rgba(255,255,255,.18) }
.rail .search svg{ left:12px; width:15px; height:15px; color:#8C8279 }
.rail .search kbd{ display:none }
/* the results panel is on a dark rail but is a light surface, like everywhere */
.rail .search .results{ left:0; right:auto; width:min(420px, 78vw); z-index:60 }

/* ── who you are, at the bottom, furthest from the work ──────────────── */
.rail .railme{ display:flex; align-items:center; gap:6px; margin-top:8px }
/* Both of these are white-surface rules in noti.css, written for a cream
   page. Dropped into the dark rail unchanged they gave a white pill with
   white text on it — the name was there the whole time and simply could not
   be seen. */
/* A rail is 190px wide inside its padding, and an avatar plus a sign-out
   button take half of it. "Patrick Le…" is worse than no name — a truncated
   identity is the one string on the screen somebody needs to read whole, so
   the two controls give the name its room rather than the other way round. */
.rail .railme .who{ flex:1; min-width:0; display:flex; align-items:center;
  gap:8px; padding:6px 4px; border-radius:11px; text-align:left;
  background:none; box-shadow:none }
.rail .railme .who > :first-child{ width:30px; height:30px; font-size:11.5px;
  flex:none }
.rail .railme .who:hover{ background:rgba(255,255,255,.06) }
.rail .railme .nm{ min-width:0 }
.rail .railme .nm b{ display:block; color:#fff; font-size:13px; font-weight:700;
  letter-spacing:-.01em; white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis }
.rail .railme .nm > span{ display:block; color:#8C8279; font-size:11.5px;
  font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.rail .railme .rnd{ flex:none; width:30px; height:30px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; color:#A69C92;
  background:rgba(255,255,255,.07); box-shadow:none }
.rail .railme .rnd:hover{ background:rgba(255,255,255,.08); color:#fff }
.rail .railme .rnd svg{ width:16px; height:16px; stroke:currentColor; fill:none;
  stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round }

/* the nav has to scroll on a short window, and the foot has to stay put.
   noti.css makes .rnav flex:none, so min-height alone never let it shrink:
   on a laptop with Settings open (eleven sections) the rail simply cut off
   its own bottom — the person and Sign out with it (owner, 26 Sep). */
.rail .rnav{ flex:1 1 auto; overflow-y:auto; min-height:0; overscroll-behavior:contain }
/* A shorter screen gets a tighter rail before it has to scroll at all. */
@media (max-height:860px){
  .rail .railslot{ padding-bottom:10px }
  .rail .ri{ padding-top:7px; padding-bottom:7px }
  .rail .risub{ padding-top:5px; padding-bottom:5px }
  .rail .railfoot{ padding-top:10px }
}
.rail .railfoot{ margin-top:auto; padding-top:14px; padding-bottom:2px }


/* ── the cabinet on a phone ───────────────────────────────────────────
   The board is 560 world pixels wide and a phone is 390. It was simply
   overflowing: bricks cut off at the right edge, both leaderboards off the
   screen entirely, and a hint reading "move the mouse anywhere".

   The drawing buffer stays 560x320 — the game keeps its own coordinates and
   nothing in its logic changes — and CSS scales the result into whatever
   width there is. Pointer positions are mapped back through that ratio in
   arcade.js, which is the half that makes it playable rather than just
   visible. */
@media (max-width:860px){
  .ark-play{ padding:0 10px; gap:10px }
  .ark-board{ width:100%; max-width:560px; height:auto; aspect-ratio:560 / 320;
    /* a drag on the board is a game input, never a page scroll */
    touch-action:none }
  .ark-play{ touch-action:none }
  .ark-hud{ width:100%; gap:10px; font-size:11.5px; flex-wrap:wrap }
  /* the sidework is drawn beside the board; there is no beside on a phone */
  .ark-surround{ display:none }

  .ark-panel h3{ font-size:30px; letter-spacing:.1em }
  .ark-panel .play{ padding:12px 30px }
  .ark-panel .hs{ font-size:11.5px; padding:0 20px; text-align:center }
  .ark-panel .back{ top:10px; left:12px }
}

/* ── the boards at the end, on a phone ────────────────────────────────
   The card grows to hold them and scrolls if it has to, because a game-over
   card taller than the cabinet would be cut off by the cabinet's own
   overflow. Monospace and small caps: it is a score table, and a score table
   that looks like the rest of the product stops looking like an arcade. */
.ark-over .ark-card .ark-boards{ display:flex; flex-direction:column; gap:14px;
  margin-top:16px; width:100%; text-align:left }
.ark-over .ark-card{ max-height:82%; overflow-y:auto; padding:18px 20px }
.ark-boards h5{ font:800 9.5px/1 ui-monospace, monospace; letter-spacing:.13em;
  text-transform:uppercase; color:color-mix(in srgb, var(--g,#7BFF9E) 58%, transparent);
  padding-bottom:6px; border-bottom:1px solid
    color-mix(in srgb, var(--g,#7BFF9E) 22%, transparent) }
.ark-boards ol{ list-style:none; margin:0; padding:0 }
.ark-boards li{ display:flex; align-items:baseline; gap:9px; padding:5px 0;
  font:600 11.5px/1.3 ui-monospace, monospace;
  color:color-mix(in srgb, var(--g,#7BFF9E) 62%, transparent) }
.ark-boards li.me{ font-weight:800;
  color:color-mix(in srgb, var(--g,#7BFF9E) 96%, transparent) }
.ark-boards li b{ font-weight:inherit; opacity:.6; min-width:11px }
.ark-boards li span{ flex:1; min-width:0 }
.ark-boards li em{ display:block; font-style:normal; font-size:9.5px;
  opacity:.62; margin-top:2px }
.ark-boards li i{ font-style:normal; font-variant-numeric:tabular-nums }

/* ── the cabinet hugs the board on a phone ────────────────────────────
   On a wide screen the space either side of the board is not empty: it holds
   the surround and the two high-score tables. None of that is drawn on a
   phone, so a fixed 430px cabinet was a large black rectangle with a small
   game in the middle of it. Here it wraps its own contents.

   .ark-play is absolutely positioned on desktop, which is how the same
   rectangle grows from status to Arcade to game without reflowing the page.
   On a phone it goes back into the flow so the hero can measure it. */
@media (max-width:860px){
  /* ── on a phone, the game IS the screen ────────────────────────────
     The cabinet was a 177px strip at the top with six hundred pixels of
     frozen Home underneath it — too small to play on and the wrong thing
     to be looking at. The page is already locked behind it while a game
     runs (html.arcade-on), so there was nothing being kept in view; it was
     just Home, held still, out of reach.

     Fixed and full-bleed, with the board centred in it. height is beaten
     with !important because the engine writes an inline height on the hero
     for the desktop animation, where the rectangle grows in place. */
  .home-hero.ark-playing{ position:fixed; inset:0; z-index:60;
    height:auto !important; border-radius:0; margin:0 !important;
    display:flex; flex-direction:column; justify-content:center;
    padding:calc(10px + env(safe-area-inset-top)) 10px
            calc(14px + env(safe-area-inset-bottom)) }
  .home-hero.ark-playing .ark-biz,
  .home-hero.ark-playing .home-mark{ display:none }
  .home-hero.ark-playing .ark-play{ position:relative; inset:auto;
    display:flex; height:auto }
  /* ── Stop sits IN the row, not over the board ──────────────────────
     It was absolutely positioned 8px down from the top of the cabinet and
     38px tall, while the row it was meant to share was 23px — so it
     straddled the HUD and the top-right corner of the board, over live
     play. Same row, same height, same baseline. */
  .home-hero.ark-playing .ark-hud{ padding:0 4px; min-height:38px;
    align-items:center; padding-right:82px }
  .ark-stop{ top:0; right:0; min-height:34px; padding:0 14px }

  /* The glow is atmosphere behind a status panel. Behind a game it is a
     large orange blob in the middle of the thing being looked at. */
  .home-hero.ark-playing::after{ opacity:0 }

  /* Every pixel of width is a bigger board, and the board is why anybody
     is here. */
  .home-hero.ark-playing{ padding-left:6px; padding-right:6px }

  /* the panel still needs a box to sit in before PLAY is pressed */
  .home-hero.ark-open:not(.ark-playing){ min-height:300px }
}

/* While a game is running the whole screen is the controller, so a drag must
   not also scroll the page out from under the paddle. */
html.arcade-on, html.arcade-on body{ touch-action:none; overscroll-behavior:none }

/* ── the way out, during the game ─────────────────────────────────────
   The panel's Back button is behind pointer-events:none while a game is
   running, so on a phone the only exit was to reload the page. This one sits
   on the cabinet itself and is the same call Esc makes. */
.ark-stop{ position:absolute; top:12px; right:12px; z-index:6;
  background:rgba(255,255,255,.1); color:rgba(255,255,255,.72); border:0;
  border-radius:99px; padding:8px 15px; font:inherit; font-size:12px;
  font-weight:700; letter-spacing:.02em; cursor:pointer;
  min-height:var(--tap); display:none; align-items:center }
.home-hero.ark-playing .ark-stop{ display:flex }
.ark-stop:hover{ background:rgba(255,255,255,.18); color:#fff }

@media (max-width:860px){
  /* the HUD was wrapping to two lines, which is where most of the black above
     the board was coming from */
  /* One row: the numbers, the hint, and the way out — all on the same
     baseline. This block used to set its own top:8px, which is exactly the
     8px Stop was sitting below the row it belongs to. */
  .home-hero.ark-playing .ark-hud{ flex-wrap:nowrap; font-size:11px; gap:7px;
    padding:0 82px 0 4px; min-height:34px; align-items:center }
  .home-hero.ark-playing .ark-hud .sp{ margin-left:auto; text-align:right;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
  .home-hero.ark-playing .ark-stop{ top:0; right:0; padding:0 14px;
    min-height:34px }
}

/* ═══════════════════════════════════════════════════════════════════════
   ADD TO NOTI — the modules screen, and the one row that opens it.

   Not an app store. An app store is a place you browse; this is a place you
   assemble the thing you already use. So: no hero, no badges, no "featured".
   A list of plain rows, each saying what it does and where it lands, and one
   panel that answers everything before the button.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── the door, at the foot of the rail ───────────────────────────────── */
.rail .rsep{ height:1px; background:rgba(255,255,255,.1); margin:10px 12px }
.rail .ri.radd{ color:#8C8279 }
.rail .ri.radd svg{ width:17px; height:17px }
.rail .ri.radd:hover{ color:#fff; background:rgba(255,255,255,.06) }

/* No cap, for the same reason Home has none: a fixed maximum is only ever
   right for one window, and on a wide screen it leaves a quarter of the page
   as dead cream. The grid is auto-fill, so more width is simply more tiles
   per row — which is what a wall of things you pick should do. */
.mod-top h1{ font-size:28px; font-weight:800; letter-spacing:-.035em;
  line-height:34px }
.mod-top p{ font-size:14.5px; color:var(--text-2); margin-top:6px;
  font-weight:500 }


@media (min-width:1000px){
    /* the panel follows you down a long catalogue */
  .mod-side{ position:sticky; top:14px }
}

/* ── a module, as a till tile ────────────────────────────────────────
   The tile itself is .ptile, borrowed whole from Sell. Only the two states
   Sell does not have are added here: active, and not-built-yet. */
.ptile.on{ background:var(--mint) }
.ptile.on .st{ color:var(--mint-d2); font-weight:700 }
.ptile.on:hover{ border-color:var(--mint-d2); background:var(--mint) }
/* Dimmed but still tappable — the panel is where somebody finds out what a
   module will do and when, and that is worth reading before it exists. */
.ptile.later{ opacity:.52 }
.ptile.later .pr{ color:var(--faint) }
.ptile.later:hover{ opacity:.8; border-color:var(--line) }

/* ── the three groups ─────────────────────────────────────────────────
   Quiet headings, not section cards: the boundary only has to be enough for
   the eye to stop at, and a boxed group inside a boxed card is two frames
   around the same thing. */
.pgroup{ padding:18px 20px 9px }
.pgroup:first-child{ padding-top:4px }
.pgroup h3{ font-size:11px; font-weight:800; letter-spacing:.13em;
  text-transform:uppercase; color:var(--text-2); display:flex;
  align-items:center; gap:8px }
.pgroup h3 span{ font-size:11px; font-weight:800; color:var(--faint);
  font-variant-numeric:tabular-nums; letter-spacing:0 }
.pgroup p{ font-size:12.5px; color:var(--faint); font-weight:500;
  margin-top:4px }

/* ── Base, which is not a module ─────────────────────────────────────── */
.mod-base{ padding:0 20px 20px }
.mod-base > p{ font-size:13.5px; color:var(--mid); line-height:19px }
.mod-base .chips{ display:flex; flex-wrap:wrap; gap:7px; margin-top:14px }
.mod-base .chips span{ font-size:12.5px; font-weight:700; padding:7px 13px;
  border-radius:99px; background:var(--mint); color:var(--mint-d2) }

/* ── the i, on the tile ──────────────────────────────────────────────
   Small, quiet, and in the corner the eye is not reading. Everything worth
   knowing before spending money is behind it, so it has to be reachable —
   but a tile is a price and a place, and an explanation on all thirty-six
   would be a wall of paragraphs. */
.ptile{ position:relative }
.tinfo{ position:absolute; top:8px; right:8px; width:20px; height:20px;
  border-radius:50%; display:flex; align-items:center; justify-content:center;
  font-size:11px; font-weight:800; font-style:italic; line-height:1;
  color:var(--faint); background:rgba(26,22,19,.05); cursor:pointer;
  transition:.12s }
.ptile:hover .tinfo{ background:rgba(26,22,19,.1); color:var(--mid) }
.tinfo:hover{ background:var(--ink) !important; color:#fff !important }
.tinfo:focus-visible{ outline:2.5px solid var(--orange-btn); outline-offset:2px }

/* ── picked ──────────────────────────────────────────────────────────
   The till marks a low line by tinting it. A picked module is the same idea
   at higher contrast, because this one is a choice somebody is making rather
   than a fact they are reading. */
.ptile.picked{ background:var(--ink); border-color:var(--ink) }
.ptile.picked b{ color:#fff }
.ptile.picked .pr{ color:#fff }
.ptile.picked .st{ color:rgba(255,255,255,.62) }
.ptile.picked .tinfo{ background:rgba(255,255,255,.16); color:rgba(255,255,255,.8) }
.ptile.picked:hover{ background:#2A2420; border-color:var(--orange) }

/* ── the basket ──────────────────────────────────────────────────────
   The till's own cart, holding modules instead of jars. */
.modside .bempty{ padding:4px 20px 22px }
.modside .bempty p{ font-size:13px; color:var(--text-2); line-height:19px }
.modside .cline.bundle{ background:var(--mint) }
.modside .cline.bundle .bd b{ color:var(--mint-d2) }
.modside .cline.bundle .bd span{ color:var(--mint-d2); opacity:.8 }
.modside .cline .drop{ width:24px; height:24px; border-radius:50%; flex:none;
  color:var(--faint); font-size:15px; line-height:1; display:flex;
  align-items:center; justify-content:center }
.modside .cline .drop:hover{ background:var(--peach); color:var(--peach-d) }
.modside .saved{ font-size:12.5px; font-weight:700; color:var(--mint-d2);
  padding:12px 20px 0; line-height:18px }

/* the near miss. An offer, styled as one — never pre-applied. */
.nearmiss{ display:block; width:100%; text-align:left; margin:12px 14px 0;
  width:calc(100% - 28px); background:var(--butter); border:0;
  border-radius:var(--r3); padding:13px 15px; cursor:pointer; font:inherit }
.nearmiss b{ display:block; font-size:13px; font-weight:800;
  color:var(--butter-d) }
.nearmiss span{ display:block; font-size:12px; color:var(--butter-d);
  opacity:.85; margin-top:3px; line-height:17px }
.nearmiss:hover{ filter:brightness(.97) }

.modside .ends{ font-size:11.5px; color:var(--text-2); padding:0 20px 14px;
  line-height:17px; font-weight:500 }
.modside .carttotal{ margin-top:14px }

/* ── the modal behind the i ──────────────────────────────────────────── */
.about .ic svg{ width:24px; height:24px; color:var(--mid); stroke:currentColor;
  fill:none; stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round }
.about .say{ font-size:14px; color:var(--mid); margin-top:11px; line-height:20px }
.about .fact{ border-top:1px solid var(--line); margin-top:16px; padding-top:13px }
.about .fact > span{ display:block; font-size:10.5px; font-weight:800;
  letter-spacing:.12em; text-transform:uppercase; color:var(--faint) }
.about .fact > b{ display:block; font-size:14.5px; font-weight:800;
  letter-spacing:-.02em; margin-top:5px }
.about .fact > small{ display:block; font-size:12.5px; color:var(--text-2);
  margin-top:4px; line-height:18px; font-weight:500 }
.about .fact.need > b{ color:var(--peach-d) }
.about .cost{ border-top:1px solid var(--line); margin-top:16px; padding-top:15px }
.about .cost b{ font-size:25px; font-weight:800; letter-spacing:-.035em }
.about .cost > span{ font-size:12.5px; color:var(--text-2); font-weight:600;
  margin-left:7px }
.about .cost small{ display:block; font-size:12.5px; color:var(--mint-d2);
  font-weight:700; margin-top:8px; line-height:18px }
.about .ends{ font-size:12px; color:var(--text-2); margin-top:12px;
  line-height:17px }

/* ── the screen it is actually being used on ─────────────────────────
   The till splits at 1000px and so does this. Below that the basket is not a
   column any more — it is the bar at the bottom of a checkout, which is what
   a phone has room for and what a thumb expects. */
@media (max-width:1000px){
  .mods .tillwrap{ grid-template-columns:1fr }
  .mods .modside{ position:sticky; bottom:0; z-index:30;
    box-shadow:0 -14px 30px -18px rgba(26,22,19,.3) }
  .mods .modside .cartlines{ max-height:32vh }
}
@media (max-width:699px){
  .mod-top h1{ font-size:23px; line-height:28px }
  .mod-top p{ font-size:13.5px }
  .mods .pgrid{ grid-template-columns:repeat(auto-fill,minmax(136px,1fr));
    gap:8px; padding:0 12px 14px }
  .mods .ptile{ padding:13px 13px }
  .mods .ptile b{ font-size:13.5px }
  .mods .ptile .pr{ font-size:17px; margin-top:7px }
  .mods .cats{ flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none;
    padding:0 14px 12px }
  .mods .cats::-webkit-scrollbar{ display:none }
  .mods .cat{ flex:none }
  .pgroup{ padding:14px 14px 7px }
}


.mod-top h1{ font-size:28px; font-weight:800; letter-spacing:-.035em;
  line-height:34px }
.mod-top p{ font-size:14.5px; color:var(--text-2); margin-top:6px;
  font-weight:500 }


@media (min-width:1000px){
    /* the panel follows you down a long catalogue */
  .mod-side{ position:sticky; top:14px }
}

/* ── the three groups ─────────────────────────────────────────────────
   Quiet headings, not section cards: the boundary only has to be enough for
   the eye to stop at, and a boxed group inside a boxed card is two frames
   around the same thing. */
.pgroup{ padding:18px 20px 9px }
.pgroup:first-child{ padding-top:4px }
.pgroup h3{ font-size:11px; font-weight:800; letter-spacing:.13em;
  text-transform:uppercase; color:var(--text-2); display:flex;
  align-items:center; gap:8px }
.pgroup h3 span{ font-size:11px; font-weight:800; color:var(--faint);
  font-variant-numeric:tabular-nums; letter-spacing:0 }
.pgroup p{ font-size:12.5px; color:var(--faint); font-weight:500;
  margin-top:4px }

/* ── Base, which is not a module ─────────────────────────────────────── */
.mod-base{ padding:0 20px 20px }
.mod-base > p{ font-size:13.5px; color:var(--mid); line-height:19px }
.mod-base .chips{ display:flex; flex-wrap:wrap; gap:7px; margin-top:14px }
.mod-base .chips span{ font-size:12.5px; font-weight:700; padding:7px 13px;
  border-radius:99px; background:var(--mint); color:var(--mint-d2) }

/* ── the panel ───────────────────────────────────────────────────────── */
.modside{ padding:20px 22px 22px }
.modp{ background:none; border-radius:0; padding:0 }
.modp.empty{ text-align:center; padding:26px 4px; color:var(--text-2) }
.modp.empty .ic{ opacity:.35; margin-bottom:12px }
.modp.empty b{ display:block; font-size:15px; color:var(--ink) }
.modp.empty p{ font-size:13px; margin-top:6px; line-height:19px }
.modp .ic svg{ width:24px; height:24px; color:var(--mid); stroke:currentColor;
  fill:none; stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round }
.modp h3{ font-size:19px; font-weight:800; letter-spacing:-.03em;
  margin-top:13px }
.modp .say{ font-size:13.5px; color:var(--mid); margin-top:7px;
  line-height:20px }

.modp .fact{ border-top:1px solid var(--line); margin-top:17px; padding-top:14px }
.modp .fact > span{ display:block; font-size:10.5px; font-weight:800;
  letter-spacing:.12em; text-transform:uppercase; color:var(--faint) }
.modp .fact > b{ display:block; font-size:14.5px; font-weight:800;
  letter-spacing:-.02em; margin-top:5px }
.modp .fact > small{ display:block; font-size:12.5px; color:var(--text-2);
  margin-top:4px; line-height:18px; font-weight:500 }
.modp .fact.need > b{ color:var(--peach-d) }

.modp .cost{ border-top:1px solid var(--line); margin-top:17px; padding-top:16px }
.modp .cost b{ font-size:26px; font-weight:800; letter-spacing:-.035em;
  font-variant-numeric:tabular-nums }
.modp .cost > span{ font-size:12.5px; color:var(--text-2); font-weight:600;
  margin-left:7px }
.modp .cost small{ display:block; font-size:12.5px; color:var(--mint-d2);
  font-weight:700; margin-top:8px; line-height:18px }

.modp .go{ margin-top:18px }
.modp .go button{ width:100%; border:0; border-radius:99px; min-height:46px;
  font:inherit; font-size:14px; font-weight:800; cursor:pointer;
  letter-spacing:-.01em }
.modp .go .b1{ background:var(--orange-btn); color:#fff }
.modp .go .b2{ background:var(--cream); color:var(--ink) }
.modp .go button:disabled{ opacity:.55; cursor:default }
.modp .ends{ font-size:12px; color:var(--text-2); margin-top:9px;
  text-align:center; font-weight:500; line-height:17px }


/* a bundle that exists and cannot be reached yet: information, not an offer,
   so it is a line of text rather than a button */

/* ── the stage, away from Home ────────────────────────────────────────
   Home grows its hero in place. Everywhere else the cabinet floats over the
   page, centred, with the page dimmed behind it — because there is no dark
   rectangle on Money to grow, and inventing one in the layout would push the
   work down every time somebody glanced at the logo.

   It carries .home-hero, so every rule the cabinet already has applies
   unchanged: the glow, the panel, the playfield, the leaderboards. */
.ark-float{ display:none; position:fixed; z-index:200;
  left:50%; top:50%; transform:translate(-50%,-50%);
  width:min(1000px, 94vw);
  box-shadow:0 40px 120px -20px rgba(8,7,6,.75),
             0 0 0 100vmax rgba(8,7,6,.62) }
.ark-float.ark-open{ display:block }
@media (max-width:860px){
  .ark-float{ width:94vw }
}
@media (prefers-reduced-motion:no-preference){
  .ark-float.ark-open{ animation:ark-in .26s cubic-bezier(.2,.9,.3,1) }
}
@keyframes ark-in{ from{ opacity:0; transform:translate(-50%,-48%) scale(.98) }
                   to{ opacity:1 } }


/* ── the panel, as three different things ─────────────────────────────
   A plan somebody is ON, the modules that are ON, and a total. They were all
   cart lines, which made the plan look removable and gave four rows reading
   $0 a cross each — a cart that looks broken rather than a bill that is
   simply small. */
.bplan{ margin:0 14px; padding:14px 16px; border-radius:var(--r3);
  background:var(--ink); color:#fff }
.bplan .top{ display:flex; align-items:baseline; gap:10px }
.bplan b{ font-size:14.5px; font-weight:800; letter-spacing:-.02em; flex:1;
  min-width:0 }
.bplan .mono{ font-size:17px; font-weight:800; flex:none }
.bplan small{ display:block; font-size:11.5px; color:rgba(255,255,255,.55);
  font-weight:600; margin-top:3px }

.bhead{ font-size:10.5px; font-weight:800; letter-spacing:.12em;
  text-transform:uppercase; color:var(--faint); padding:16px 20px 7px }
.bon{ padding:0 14px; display:flex; flex-direction:column; gap:5px }
.bline{ display:flex; align-items:center; gap:10px; padding:10px 13px;
  border-radius:var(--r3); background:var(--cream-2) }
.bline .bd{ flex:1; min-width:0 }
.bline .bd b{ display:block; font-size:13.5px; font-weight:700; line-height:1.25 }
.bline .bd span{ display:block; font-size:11.5px; color:var(--faint);
  font-weight:600; margin-top:2px }
.bline .amt{ font-size:14px; font-weight:700; flex:none }
/* included is a STATE, not a price of zero — so it is a word, not a number */
.bline .tag-free{ flex:none; font-size:11px; font-weight:800; padding:4px 9px;
  border-radius:99px; background:var(--mint); color:var(--mint-d2) }
.bline .manage{ flex:none; font-size:11.5px; font-weight:700;
  color:var(--text-2); padding:5px 8px; border-radius:99px; background:none }
.bline .manage:hover{ background:var(--line); color:var(--ink) }

.bfree{ font-size:13px; color:var(--mint-d2); font-weight:700;
  padding:18px 20px 0; line-height:18px }


/* ── the standing bill ────────────────────────────────────────────────
   The plan and everything already on, above whatever is being added. It is
   there before anybody taps anything, because "what am I paying" is a
   question this screen should answer without being asked. */
.modside .cline.plan{ background:var(--line-2) }
.modside .cline.plan .bd b{ font-weight:800 }
.modside .adding{ font-size:10.5px; font-weight:800; letter-spacing:.12em;
  text-transform:uppercase; color:var(--faint); padding:14px 20px 7px }
.modside .wasline{ font-size:11.5px; color:var(--text-2); padding:0 20px 2px;
  text-align:right; font-weight:500 }
.about .fact.off > b{ color:var(--peach-d) }

/* a line in the basket that is not optional: the platform the catalogue
   needs, priced with everything else rather than discovered at the end */
.modside .cline.required{ background:var(--attn-l) }
.modside .cline.required .bd b{ color:var(--attn) }
.modside .cline.required .bd span{ color:var(--attn); opacity:.85 }

/* something on, at no charge: the number is real and it is zero, so it is
   shown quietly rather than dressed up as a discount */
.modside .cline.free .amt{ color:var(--mint-d2) }
.modside .cline.free .bd span{ color:var(--mint-d2) }
.ptile.on .pr{ font-size:15px; letter-spacing:-.02em }

/* ── the floor ────────────────────────────────────────────────────────
   What every business has, stated once above everything else. Not a tile and
   not a filter: it is not a choice, and putting it in a grid of choices was
   what made "what is included" a question in the first place. */
.mods .included{ padding:20px 22px 22px; margin-bottom:14px }
.mods .included .ch{ padding:0 0 14px }
.mods .included .free{ font-size:12px; font-weight:700; color:var(--mint-d2);
  background:var(--mint); padding:5px 12px; border-radius:99px }

/* Switches, and they have to LOOK like switches. Green pills with a dot read
   as labels — which is what they were before they became controls, and
   nothing about them said they could be pressed.

   A tick box is the only shape everybody already knows means "this is a
   choice, and it is currently this way". Off is an empty box on a plain
   surface, not merely a duller green, because an area that is off should look
   absent rather than quiet. */
.mods .rails{ display:flex; flex-wrap:wrap; gap:8px }
.railchip{ font-size:13px; font-weight:700; padding:8px 14px 8px 10px;
  border-radius:99px; background:var(--white); color:var(--mid);
  border:1.5px solid var(--line); cursor:pointer; font-family:inherit;
  display:flex; align-items:center; gap:9px; min-height:38px;
  transition:.12s }
.railchip .tick{ width:17px; height:17px; border-radius:5px; flex:none;
  border:1.5px solid var(--line-2); background:var(--cream-2);
  position:relative; transition:.12s }
.railchip.on{ background:var(--mint); color:var(--mint-d2);
  border-color:transparent }
.railchip.on .tick{ background:var(--mint-d2); border-color:var(--mint-d2) }
/* the tick itself, drawn rather than fetched */
.railchip.on .tick::after{ content:''; position:absolute; left:5px; top:2px;
  width:4px; height:8px; border:solid #fff; border-width:0 2px 2px 0;
  transform:rotate(43deg) }
.railchip:hover:not(:disabled){ border-color:var(--faint) }
.railchip.on:hover:not(:disabled){ border-color:var(--mint-d2) }
.railchip em{ font-style:normal; font-size:10.5px; font-weight:700;
  letter-spacing:.07em; text-transform:uppercase; opacity:.5 }
.railchip:disabled{ cursor:default }
.railchip:focus-visible{ outline:2.5px solid var(--orange-btn);
  outline-offset:2px }

.mods .included .hint{ font-size:12px; font-weight:600; color:var(--text-2) }
.mods .included > p{ font-size:12.5px; color:var(--text-2); margin-top:14px;
  line-height:18px; max-width:76ch }

/* ── the plan, changing ───────────────────────────────────────────────
   Base is the single biggest number on this screen. As a line among the
   modules it read as one more item; here it reads as what it is — the plan
   moving, with the modules underneath it. */
.bplan.up{ background:var(--orange-btn) }
.bplan.up .was{ font-weight:700; color:rgba(255,255,255,.72) }
.bplan.up small{ color:rgba(255,255,255,.85) }

/* ── the page sits together ───────────────────────────────────────────
   Two cards floating apart with a band of cream between them read as two
   screens. They are one answer in two halves: here is what you have, here is
   what you can add to it. */
.mods .included{ margin-bottom:0; padding:18px 22px 20px }
.mods .mod-head{ display:grid; grid-template-columns:1fr; gap:14px;
  margin-bottom:14px }
@media (min-width:1001px){
  /* the same two columns as the grid below it, so the page reads as one
     object rather than two that happen to be stacked */
  .mods .mod-head{ grid-template-columns:1fr 340px; align-items:stretch }
}

/* ── what the next step costs ─────────────────────────────────────────
   The column beside "what you already have" was empty, and the question that
   belongs in that space is "what does the next step cost". Answered once,
   where it is asked, rather than discovered at the bottom of a basket. */
.baseabout{ padding:18px 20px 20px; display:flex; flex-direction:column }
.baseabout h2{ font-size:14.5px; font-weight:800; letter-spacing:-.02em }
.baseabout .p{ display:flex; align-items:baseline; gap:8px; margin-top:9px }
.baseabout .p b{ font-size:30px; font-weight:800; letter-spacing:-.04em }
.baseabout .p span{ font-size:11.5px; color:var(--text-2); font-weight:600 }
.baseabout > p{ font-size:12.5px; color:var(--mid); line-height:18px;
  margin-top:10px }
.baseabout ul{ list-style:none; margin:12px 0 0; padding:0; display:flex;
  flex-direction:column; gap:6px }
.baseabout li{ font-size:12px; color:var(--text-2); font-weight:600;
  padding-left:16px; position:relative; line-height:17px }
.baseabout li::before{ content:''; position:absolute; left:0; top:6px;
  width:6px; height:6px; border-radius:50%; background:var(--orange) }
.baseabout.ison li::before{ background:var(--mint-d2) }
.baseabout.ison h2{ color:var(--mint-d2) }


/* ═══════════════════════════════════════════════════════════════════════
   CUSTOMERS — the first relationship area, and the two shapes every other
   area will borrow: a comparison table, and an object page. §7 §8

   Almost nothing here is customer-specific on purpose. .sys-dim, .sys-bad,
   .sys-chipb, .kvs and the trail are all going to be wanted by Jobs and
   Money in a fortnight, and naming them after Customers now would mean
   either three copies or a rename later.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── two words the tables keep needing ───────────────────────────────── */
.sys-dim{ color:var(--text-2); opacity:.75 }
.sys-bad{ color:var(--peach-d) }
.sys-warn{ color:var(--attn) }  /* wants attention, is not yet wrong */
.sys-t em.sys-dim{ font-style:normal; font-weight:600; margin-left:4px }

/* ── the filter strip, which is also the trend line ──────────────────── */
.cust-filters{ display:flex; align-items:center; gap:6px; flex-wrap:wrap;
  margin-bottom:10px }
.sys-chipb{ font:inherit; cursor:pointer; border-radius:999px;
  border:1px solid var(--line); background:var(--white); color:var(--text-2);
  font-size:12px; font-weight:700; padding:0 12px; min-height:30px;
  display:inline-flex; align-items:center; gap:6px }
@media (pointer:coarse){ .sys-chipb{ min-height:var(--tap); padding:0 15px } }
.sys-chipb:hover:not(:disabled){ border-color:var(--ink); color:var(--ink) }
.sys-chipb.on{ background:var(--ink); border-color:var(--ink); color:#fff }
.sys-chipb:disabled{ opacity:.4; cursor:default }
.sys-chipb em{ font-style:normal; font-variant-numeric:tabular-nums;
  opacity:.65; font-weight:600 }
.sys-chipb.on em{ opacity:.8 }

.cust-find{ margin-left:auto; min-width:0 }
.cust-find input{ font:inherit; font-size:13px; border-radius:999px;
  border:1px solid var(--line); background:var(--white); color:var(--ink);
  padding:9px 15px; min-height:36px; width:min(240px, 44vw) }
.cust-find input:focus{ border-color:var(--ink) }

/* ── the name cell. A face and a place, on one line ──────────────────── */
.cust-name{ display:inline-flex; align-items:center; gap:10px; min-width:0 }
.cust-name .m{ min-width:0 }
.cust-name .m b{ display:block; font-weight:700; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis }
.cust-name .m span{ display:block; font-size:12px; color:var(--text-2) }

/* ── the object page's two halves ────────────────────────────────────── */
.cust-cols{ display:grid; gap:var(--s5); grid-template-columns:1fr }
@media (min-width:860px){ .cust-cols{ grid-template-columns:1fr 1fr } }

.kvs{ display:flex; flex-direction:column; gap:0 }
.kv{ display:flex; align-items:baseline; gap:var(--s4);
  padding:7px 0; border-bottom:1px solid var(--line-2) }
.kv:last-child{ border-bottom:0 }
/* A percentage label column was the actual cause of the stretched look:
   40% of a wide card is over five hundred pixels, so "Owner" sat at the far
   left and "Coast Road IGA" a hand's width away. Capped, the pair reads as
   a pair at any card width — which is what made the page measure a symptom
   rather than the fix. */
.kv > span{ font-size:12px; color:var(--text-2); font-weight:600;
  width:min(40%, 190px); flex:none }
.kv > b{ font-size:13.5px }
.kv > b{ font-weight:700; min-width:0; overflow-wrap:anywhere }

.cust-notes{ font-size:var(--t-body); line-height:21px; color:var(--ink);
  white-space:pre-wrap }

/* ── activity. One timeline, three sources ───────────────────────────── */
.cust-trail{ display:flex; flex-direction:column }
.cust-ev{ display:flex; align-items:baseline; gap:var(--s4);
  padding:8px 0; border-bottom:1px solid var(--line-2) }
.cust-ev:last-child{ border-bottom:0 }
.cust-ev .w{ font-size:12.5px; color:var(--text-2); font-variant-numeric:tabular-nums;
  width:120px; flex:none }
.cust-ev b{ font-weight:700 }
.cust-ev .sys-dim{ margin-left:auto; font-size:12.5px }

@media (max-width:699px){
  .cust-find{ margin-left:0; width:100% }
  .cust-find input{ width:100% }
  .cust-ev{ flex-wrap:wrap; gap:4px var(--s3) }
  .cust-ev .w{ width:auto; order:3; flex-basis:100% }
  .cust-ev .sys-dim{ margin-left:0 }
}

/* ── the four figures on an object page ──────────────────────────────── */
.sys-figs{ display:grid; gap:1px; background:var(--line);
  border:1px solid var(--line); border-radius:var(--r3); overflow:hidden;
  grid-template-columns:repeat(2, 1fr); margin-bottom:10px }
@media (min-width:760px){ .sys-figs{ grid-template-columns:repeat(4, 1fr) } }
.sys-fig{ background:var(--white); padding:10px 14px 11px;
  display:flex; flex-direction:column; gap:1px; min-width:0 }
.sys-fig .k{ font-size:10px; font-weight:800; letter-spacing:.1em;
  text-transform:uppercase; color:var(--text-2) }
.sys-fig b{ font-size:19px; font-weight:800; line-height:25px;
  font-variant-numeric:tabular-nums }
.sys-fig .s{ font-size:11.5px; color:var(--text-2) }

/* ── the next thing in the diary ─────────────────────────────────────── */
.cust-next{ display:flex; align-items:center; gap:10px; background:var(--white);
  border:1px solid var(--line); border-radius:var(--r3);
  padding:10px 14px; margin-bottom:10px }
.cust-next .m{ flex:1; min-width:0 }
.cust-next .m b{ display:block; font-weight:700 }
.cust-next .m span{ display:block; font-size:12.5px; color:var(--text-2) }

/* ── their own door ──────────────────────────────────────────────────── */
.cust-share p{ font-size:12.5px; line-height:18px; color:var(--text-2);
  margin:0 0 9px }
.cust-share .sys-b{ margin-top:2px }
.cust-url{ display:flex; gap:8px; margin-bottom:10px }
.cust-url input{ flex:1; min-width:0; font:inherit; font-size:12.5px;
  font-family:var(--m, ui-monospace, monospace);
  border:1px solid var(--line); border-radius:var(--r3);
  background:var(--cream-2); color:var(--ink); padding:9px 12px;
  min-height:var(--tap) }
.cust-url input:focus{ border-color:var(--ink) }
.cust-share.off p:first-child{ color:var(--ink) }
.cust-priv{ font-size:12px; margin-top:8px }
.cust-tags{ display:flex; flex-wrap:wrap; gap:6px }
.kv a{ color:var(--ink); text-decoration:none; border-bottom:1px solid var(--line) }
.kv a:hover{ border-bottom-color:var(--ink) }

/* ── the ··· menu ────────────────────────────────────────────────────── */
.sys-morewrap{ position:relative }
.sys-menu{ position:absolute; right:0; top:calc(100% + 6px); z-index:40;
  min-width:190px; background:var(--white); border:1px solid var(--line);
  border-radius:var(--r3); padding:6px;
  box-shadow:0 10px 30px rgba(23,27,24,.12); display:flex;
  flex-direction:column; gap:2px }
.sys-menu button{ font:inherit; font-size:13.5px; font-weight:600;
  text-align:left; background:none; border:0; cursor:pointer;
  color:var(--ink); border-radius:8px; padding:9px 11px; min-height:38px }
.sys-menu button:hover{ background:var(--cream-2) }
.sys-menu button.danger{ color:var(--peach-d) }
.sys-menu button.danger:hover{ background:var(--peach) }


/* ── the note log ────────────────────────────────────────────────────── */
.note-new{ display:flex; flex-direction:column; gap:8px; align-items:flex-start;
  margin-bottom:12px }
.note-box{ width:100%; font:inherit; font-size:13.5px; line-height:19px;
  color:var(--ink); background:var(--cream-2);
  border:1.5px solid var(--line); border-radius:var(--r3);
  padding:9px 11px; resize:vertical; min-height:56px }
.note-box:focus{ border-color:var(--ink); background:var(--white) }

.note-log{ list-style:none; margin:0; padding:0;
  border-top:1px solid var(--line-2) }
.note-log li{ padding:9px 0; border-bottom:1px solid var(--line-2) }
.note-log li:last-child{ border-bottom:0 }
.note-log .h{ display:flex; align-items:center; gap:8px; margin-bottom:2px }
.note-log .h b{ font-size:12px; font-weight:800 }
.note-log .h span{ font-size:11.5px; color:var(--text-2) }
.note-log .h .note-x{ margin-left:auto; background:none; border:0;
  cursor:pointer; color:var(--text-2); font-size:17px; line-height:1;
  padding:0 4px; opacity:0 }
.note-log li:hover .note-x, .note-x:focus-visible{ opacity:1 }
.note-log .note-x:hover{ color:var(--peach-d) }
.note-log p{ margin:0; font-size:13.5px; line-height:19px;
  white-space:pre-wrap; overflow-wrap:anywhere }
.note-none{ margin:0 0 4px }
.cust-priv{ font-size:11.5px; margin-top:10px }

/* ── ask. The only interruption the product is allowed ───────────────── */
.sys-ask{ position:fixed; inset:0; z-index:200; display:flex;
  align-items:center; justify-content:center; padding:24px;
  background:rgba(23,27,24,.44); opacity:0; transition:opacity .16s;
  -webkit-backdrop-filter:blur(2px); backdrop-filter:blur(2px) }
.sys-ask.in{ opacity:1 }
.sys-ask-box{ width:min(380px,100%); background:var(--cream);
  border-radius:16px; padding:20px 22px 18px;
  box-shadow:0 30px 70px -24px rgba(23,27,24,.55);
  transform:translateY(8px) scale(.99); transition:transform .16s cubic-bezier(.22,1,.36,1) }
.sys-ask.in .sys-ask-box{ transform:none }
.sys-ask-box h2{ font-size:17px; font-weight:800; letter-spacing:-.01em;
  line-height:23px }
.sys-ask-box p{ font-size:13.5px; line-height:19px; color:var(--text-2);
  margin-top:6px }
.sys-ask-box .go{ display:flex; gap:9px; justify-content:flex-end;
  margin-top:18px }
.sys-b.danger{ background:var(--peach-d); color:#fff }
/* A quiet button that undoes something: a ghost, in the warning colour. */
button.big.ghost.danger{ color:var(--peach-d) }
.sys-b.danger:hover{ filter:brightness(.92) }
.modside .cline .coming{ display:block; font-style:normal; font-size:11px;
  color:var(--mint-d2); opacity:.85; margin-top:3px }

/* ── the shelf. A bundle you can just take ───────────────────────────── */
.mods .shelf .ch .hint{ font-size:11.5px; color:var(--text-2) }
.shelf-say{ font-size:12.5px; line-height:18px; color:var(--text-2);
  padding:0 20px 12px; margin:0 }
/* Three across, two down. Five-and-one left a hole the width of four tiles
   and made every tile too narrow for its own sentence. */
.shelfgrid{ display:grid; gap:10px; padding:0 20px 20px;
  grid-template-columns:repeat(auto-fill, minmax(min(100%, 230px), 1fr)) }
@media (min-width:1100px){ .shelfgrid{ grid-template-columns:repeat(3, 1fr) } }
.btile{ font:inherit; text-align:left; cursor:pointer; min-width:0;
  background:var(--white); border:1.5px solid var(--line);
  border-radius:var(--r3); padding:13px 14px 12px;
  display:flex; flex-direction:column; gap:5px;
  transition:border-color .14s, background .14s }
.btile:hover{ border-color:var(--ink) }
.btile.part{ border-color:var(--mint-d2) }
.btile.picked{ background:var(--mint); border-color:var(--mint-d2) }
.btile .bh{ display:flex; align-items:baseline; gap:8px }
.btile .bh b{ font-size:14px; font-weight:800; flex:1; min-width:0;
  letter-spacing:-.01em }
.btile .bh .p{ font-size:15px; font-weight:800;
  font-variant-numeric:tabular-nums; flex:none }
.btile .bl{ font-size:12px; line-height:17px; color:var(--text-2) }
.btile .bm{ font-size:11.5px; line-height:16px; color:var(--text-2);
  opacity:.85 }
.btile .bc{ font-size:11px; color:var(--mint-d2); font-weight:700 }
.btile .bg{ display:flex; align-items:baseline; gap:8px; margin-top:4px;
  padding-top:9px; border-top:1px solid var(--line-2) }
.btile .bg em{ font-style:normal; font-size:11px; font-weight:700;
  color:var(--mint-d2); flex:1; min-width:0; line-height:15px }
.btile .take{ font-size:12px; font-weight:800; color:var(--ink); flex:none }
.btile.picked .take{ color:var(--mint-d2) }
.btile.picked .bg{ border-top-color:rgba(23,99,60,.22) }
/* The way to the rail's own settings, on the rail. Quieter than an area. */
.rail .rgear{ opacity:.62 }
.rail .rgear:hover{ opacity:1 }
.setbody .rails{ display:flex; flex-wrap:wrap; gap:8px; padding:4px 22px 0 }
.setbody .sidesay{ font-size:12.5px; line-height:18px; color:var(--text-2);
  padding:12px 22px 18px; margin:0 }

/* ── one page, one rail ──────────────────────────────────────────────── */
.mods .modmain{ display:flex; flex-direction:column; gap:14px; min-width:0 }
.mods .modrail{ display:flex; flex-direction:column; gap:14px; min-width:0 }
@media (min-width:1001px){
  /* The rail follows. A basket you have to scroll back up to read is a
     basket nobody reads. */
  .mods .modrail{ position:sticky; top:14px }
}
.btile .ball{ font-size:11px; font-weight:800; color:var(--ink) }
.mods .baseabout li b{ font-weight:800; color:var(--ink) }
.mods .baseabout li b{ font-weight:800; color:var(--ink) }
/* One line, once, under the thing it is about. Never a banner. */
.home-base{ font:inherit; font-size:12.5px; font-weight:700; cursor:pointer;
  background:none; border:0; padding:10px 0 0; color:var(--orange-btn);
  display:inline-flex; align-items:center; gap:7px }
.home-base:hover{ text-decoration:underline }
.home-base .dot{ width:7px; height:7px }

/* ═══════════════════════════════════════════════════════════════════════
   THE BOARD — the shape a table cannot make

   Three lanes on a wide screen; on a phone they stack, because three
   columns 120px wide is a board nobody can read and a horizontal scroll
   inside a vertical page is the worst of both.
   ═══════════════════════════════════════════════════════════════════════ */
.viewtog{ display:inline-flex; background:var(--cream-2); border-radius:999px;
  padding:2px; gap:2px }
.vt{ font:inherit; font-size:12px; font-weight:700; cursor:pointer;
  border:0; background:none; color:var(--text-2); border-radius:999px;
  padding:0 13px; min-height:26px }
.vt.on{ background:var(--white); color:var(--ink);
  box-shadow:0 1px 3px rgba(23,27,24,.1) }
@media (pointer:coarse){ .vt{ min-height:38px } }

.board{ display:grid; gap:10px; grid-template-columns:1fr; align-items:start }
@media (min-width:900px){ .board{ grid-template-columns:repeat(3, 1fr) } }
.lane{ background:var(--cream-2); border:1px solid var(--line);
  border-radius:var(--r3); padding:12px; min-width:0 }
.lane h3{ font-size:10.5px; font-weight:800; letter-spacing:.12em;
  text-transform:uppercase; color:var(--text-2); margin-bottom:10px;
  display:flex; align-items:center; gap:7px }
.lane h3 span{ font-variant-numeric:tabular-nums; opacity:.7 }
.lanebody{ display:flex; flex-direction:column; gap:8px }
.lane-none{ font-size:12.5px; color:var(--text-2); opacity:.7; margin:2px 0 }

.jcard{ font:inherit; text-align:left; cursor:pointer; width:100%;
  background:var(--white); border:1px solid var(--line);
  border-radius:var(--r3); padding:11px 12px;
  display:flex; flex-direction:column; gap:3px; min-width:0 }
.jcard:hover{ border-color:var(--ink) }
/* Late is a left edge, not a badge. Home's Needs You uses the same rule:
   a mark down the side reads at a glance across a whole column. */
.jcard.late{ border-left:3px solid var(--peach-d); padding-left:10px }
.jcard .jt{ font-size:13.5px; font-weight:700; line-height:18px;
  overflow-wrap:anywhere }
.jcard .jc{ font-size:12px; color:var(--text-2) }
.jcard .jf{ display:flex; align-items:baseline; gap:8px; margin-top:3px }
.jcard .jw{ font-size:12px; color:var(--text-2); font-weight:600 }
.jcard .jv{ margin-left:auto; font-size:12.5px; font-weight:800;
  font-variant-numeric:tabular-nums }
.jcard .jp{ display:flex; align-items:center; gap:6px; margin-top:6px;
  padding-top:8px; border-top:1px solid var(--line-2); font-size:11.5px;
  color:var(--text-2) }
.jcard .jp .av{ width:20px; height:20px; font-size:9px }
.jcard .nobody{ color:var(--peach-d); font-weight:700 }

.job-who{ display:inline-flex; align-items:center; gap:7px }
.job-who .av{ width:22px; height:22px; font-size:9.5px }
.sys-t em.sys-bad{ font-style:normal; font-weight:700; font-size:11.5px }

/* ── dragging a card ─────────────────────────────────────────────────── */
.board .jcard{ touch-action:none; user-select:none }
.jcard.lifted{ opacity:.3 }
.jghost{ position:fixed; left:0; top:0; z-index:300; pointer-events:none;
  box-shadow:0 18px 40px -12px rgba(23,27,24,.42); transform-origin:0 0;
  rotate:1.5deg; opacity:.97 }
.lane.over{ background:var(--mint); border-color:var(--mint-d2) }
body.dragging{ cursor:grabbing }
body.dragging *{ cursor:grabbing !important }
.linkish{ font:inherit; background:none; border:0; padding:0; cursor:pointer;
  color:var(--ink); font-weight:700;
  border-bottom:1px solid var(--line) }
.linkish:hover{ border-bottom-color:var(--ink) }

/* ── the map ─────────────────────────────────────────────────────────── */
.mapwrap{ display:grid; gap:10px; grid-template-columns:1fr; align-items:start }
@media (min-width:900px){
  .mapwrap{ grid-template-columns:minmax(0,1fr) 320px }
}
.jobmap{ height:min(62vh, 560px); border-radius:var(--r3);
  border:1px solid var(--line); background:var(--cream-2); overflow:hidden }
.map-none{ display:flex; align-items:center; justify-content:center;
  height:100%; margin:0; font-size:13px }
/* No filter on the tiles. It is a photograph: warming it just makes it look
   old, and the pins carry the only colour that means anything. */

/* Leaflet draws its own controls; they should not look like a foreign app. */
.jobmap .leaflet-control-attribution{ font-size:10px; background:rgba(255,255,255,.78);
  color:var(--text-2); padding:1px 6px; border-radius:6px 0 0 0 }
.jobmap .leaflet-control-attribution a{ color:var(--text-2) }
.jobmap .leaflet-popup-content{ font:inherit; font-size:12.5px; line-height:18px }
.jobmap .leaflet-popup-content-wrapper{ border-radius:var(--r3) }
.jobmap .leaflet-bar{ border:0; box-shadow:0 2px 10px rgba(23,27,24,.16);
  border-radius:var(--r3); overflow:hidden }
.jobmap .leaflet-bar a{ font:inherit; font-weight:700; color:var(--ink);
  width:30px; height:30px; line-height:30px; border-bottom-color:var(--line-2) }
.jobmap .leaflet-bar a:hover{ background:var(--cream-2) }



.maplist{ background:var(--white); border:1px solid var(--line);
  border-radius:var(--r3); padding:13px 14px; min-width:0 }
.maplist h3{ font-size:10.5px; font-weight:800; letter-spacing:.12em;
  text-transform:uppercase; color:var(--text-2); margin-bottom:9px;
  display:flex; gap:7px }
.maplist h3 span{ opacity:.7; font-variant-numeric:tabular-nums }
.maprows{ display:flex; flex-direction:column; max-height:44vh; overflow-y:auto }
.maprow{ font:inherit; text-align:left; cursor:pointer; background:none;
  border:0; border-bottom:1px solid var(--line-2); padding:8px 0; width:100% }
.maprow:last-child{ border-bottom:0 }
.maprow:hover{ background:var(--cream-2) }
.maprow b{ display:block; font-size:13px; font-weight:700 }
.maprow span{ display:block; font-size:11.5px; color:var(--text-2) }
.maprow.late b{ color:var(--peach-d) }
.mapmiss{ margin-top:11px; padding-top:10px; border-top:1px solid var(--line) }
.mapmiss p{ font-size:11.5px; line-height:16px; color:var(--text-2); margin:0 0 6px }
.mapmiss b{ color:var(--ink) }
.mapsay{ font-size:11px; line-height:15px; color:var(--text-2); opacity:.8;
  margin:11px 0 0; padding-top:9px; border-top:1px solid var(--line-2) }

/* ── a map on a record ───────────────────────────────────────────────── */
.recmap{ height:170px; border-radius:var(--r3); overflow:hidden;
  border:1px solid var(--line); background:var(--cream-2); margin-bottom:10px }
.recmap .leaflet-control-attribution{ font-size:9px;
  background:rgba(255,255,255,.75); padding:0 5px }
.cust-addr{ font-size:13px; line-height:18px; margin:0 0 10px }
.mapgo{ text-decoration:none; align-self:flex-start }

/* ── the shape of the money ──────────────────────────────────────────── */
.money-chart{ margin-bottom:10px }
.money-chart .ch{ display:flex; align-items:baseline; gap:10px; margin-bottom:12px }
.money-chart .ch h2{ font-size:10.5px; font-weight:800; letter-spacing:.12em;
  text-transform:uppercase; color:var(--text-2) }
.money-chart .ch .hint{ margin-left:auto; font-size:11.5px; color:var(--text-2) }
.bars{ display:flex; align-items:stretch; gap:6px; height:150px }

/* A grid, not a column of flex items. The bar's height is a percentage, and
   a percentage needs something definite to be a percentage OF — in the flex
   version it resolved against the whole 132px column, label included, so
   the tallest month pushed its own label off the bottom of the card. A 1fr
   grid track is definite, so the bar can only ever fill the space above the
   label. */
.bar{ flex:1; min-width:0; height:100%; display:grid;
  grid-template-rows:1fr auto; gap:6px; justify-items:center }
.bar .v{ align-self:end; width:100%; max-width:64px; background:var(--mid);
  border-radius:5px 5px 0 0;
  transition:height .3s cubic-bezier(.2,.8,.2,1) }
/* An empty month is a visible empty month, not a gap in the row. */
.bar .v[data-none]{ height:2px !important; background:var(--line);
  border-radius:2px }
.bar .l{ font-size:10px; font-weight:700; color:var(--text-2);
  white-space:nowrap }
/* The most recent month is the one being asked about. Ink for the rest was
   too much furniture for a cream screen — six black slabs read as the
   heaviest thing on the page and they are the least urgent. */
.bar:last-child .v{ background:var(--orange-btn) }

/* ── what is on an invoice ───────────────────────────────────────────── */
.lines{ display:flex; flex-direction:column; border-top:1px solid var(--line-2) }
.line{ display:grid; align-items:center; gap:10px;
  grid-template-columns:1fr auto 76px 84px auto;
  padding:9px 0; border-bottom:1px solid var(--line-2) }
.line .d{ font-size:13.5px; font-weight:600; min-width:0; overflow-wrap:anywhere }
.line .q{ display:inline-flex; align-items:center; gap:6px;
  font-variant-numeric:tabular-nums }
.line .q b{ min-width:20px; text-align:center; font-weight:800; font-size:13px }
.line .u,.line .t{ text-align:right; font-variant-numeric:tabular-nums;
  font-size:13px }
.line .u{ color:var(--text-2) }
.line .t{ font-weight:800 }
.qb{ width:24px; height:24px; border-radius:6px; cursor:pointer; font:inherit;
  font-size:14px; line-height:1; border:1px solid var(--line);
  background:var(--white); color:var(--ink) }
.qb:hover{ border-color:var(--ink) }
.line .drop{ width:24px; height:24px; border-radius:50%; border:0; cursor:pointer;
  background:none; color:var(--text-2); font-size:16px; line-height:1 }
.line .drop:hover{ background:var(--peach); color:var(--peach-d) }
.addline{ margin-top:12px; align-self:flex-start }
@media (max-width:640px){
  .line{ grid-template-columns:1fr auto auto; row-gap:2px }
  .line .u{ grid-column:1; font-size:11.5px }
}

/* ── picking a product ───────────────────────────────────────────────── */
.pickq{ min-height:40px; resize:none }
.picklist{ display:flex; flex-direction:column; max-height:48vh; overflow-y:auto;
  border-top:1px solid var(--line-2); margin-top:4px }
.pickrow{ font:inherit; text-align:left; cursor:pointer; background:none;
  border:0; border-bottom:1px solid var(--line-2); padding:10px 2px;
  display:flex; align-items:center; gap:10px; width:100% }
.pickrow:hover{ background:var(--cream-2) }
.pickrow .m{ flex:1; min-width:0 }
.pickrow .m b{ display:block; font-size:13.5px; font-weight:700 }
.pickrow .m span{ display:block; font-size:11.5px; color:var(--text-2) }
.pickrow .p{ font-weight:800; font-variant-numeric:tabular-nums; flex:none }

/* ── building a sale out of products ─────────────────────────────────── */
.np-lines{ display:flex; flex-direction:column; margin-bottom:8px }
.np-line{ display:grid; align-items:center; gap:10px;
  grid-template-columns:1fr auto 76px auto;
  padding:8px 0; border-bottom:1px solid var(--line-2) }
.np-line .d{ font-size:13.5px; font-weight:600; min-width:0 }
.np-line .q{ display:inline-flex; align-items:center; gap:6px }
.np-line .q b{ min-width:18px; text-align:center; font-weight:800; font-size:13px }
.np-line .t{ text-align:right; font-weight:800; font-size:13px;
  font-variant-numeric:tabular-nums }
.np-line .drop{ width:22px; height:22px; border-radius:50%; border:0;
  cursor:pointer; background:none; color:var(--text-2); font-size:15px }
.np-line .drop:hover{ background:var(--peach); color:var(--peach-d) }
.np-none{ font-size:12.5px; margin:0 0 4px }
.np-pick{ border:1px solid var(--line); border-radius:var(--r3);
  padding:9px 10px; margin-bottom:10px; background:var(--cream-2) }
.np-pick input{ width:100%; font:inherit; font-size:13px; border-radius:var(--r3);
  border:1px solid var(--line); background:var(--white); padding:8px 10px;
  min-height:38px; margin-bottom:6px }
.np-pick .picklist{ max-height:210px }
.np-total{ display:flex; align-items:baseline; gap:10px; margin-top:6px;
  padding-top:10px; border-top:1px solid var(--line) }
.np-total span{ font-size:11px; font-weight:800; letter-spacing:.12em;
  text-transform:uppercase; color:var(--text-2) }
.np-total b{ margin-left:auto; font-size:19px; font-weight:800;
  font-variant-numeric:tabular-nums }

/* ── a wide dialogue: two things to do, side by side ─────────────────── */
.sys-drawer.wide{ width:min(760px, 100%) }
.np-grid{ display:grid; gap:18px; grid-template-columns:1fr }
@media (min-width:700px){
  .np-grid{ grid-template-columns:minmax(0,1.25fr) minmax(0,1fr) }
}
/* Cards, not a rule between two columns of loose fields. The dividing line
   was doing the work a card does and doing it worse: with nothing added yet
   the left side was a heading and a wall of white, which reads as a form
   that failed rather than one waiting for you. */
.np-what, .np-who{ display:flex; flex-direction:column; min-width:0;
  gap:var(--s3); padding:var(--s4); align-self:start }
.np-what h2, .np-who h2, .np-how h2{ font-size:10.5px; font-weight:800; letter-spacing:.12em;
  text-transform:uppercase; color:var(--text-2); margin:0 }
.np-what .fld, .np-who .fld{ margin:0 }
/* 92px clipped "09:00" to "09:0" — a time input carries a picker button the
   browser draws itself and it is not part of the text width. */
.np-2up{ display:grid; grid-template-columns:1fr 124px; gap:var(--s2) }
.np-2up input[type=time]{ min-width:0 }
.np-total:empty{ display:none }

.np-adds{ display:flex; gap:8px; flex-wrap:wrap; margin-top:2px }
/* How a sale is handled, and how they paid: two answers, big enough to hit
   standing at a counter. The chosen one is filled. */
.np-how{ grid-column:1 / -1; display:flex; flex-direction:column; gap:var(--s3); padding:var(--s4) }
.np-hows{ display:flex; gap:8px; flex-wrap:wrap }
.np-hows .sys-b{ min-height:44px; flex:1 1 140px }
.np-hows .sys-b.primary{ background:var(--orange-btn); color:#fff; border-color:transparent }
.np-method{ margin-top:12px }
.np-lab{ font-size:var(--t-small); font-weight:700; color:var(--text-2); margin:0 0 6px }
.np-own-tag{ font-style:normal; font-size:10px; font-weight:800;
  letter-spacing:.06em; text-transform:uppercase; color:var(--text-2);
  margin-left:7px; opacity:.75 }

/* the typed line */
.np-own .np-orow{ display:flex; align-items:center; gap:8px }
.np-cur{ font-size:12.5px; font-weight:800; color:var(--text-2) }
.np-own #np-op{ width:110px; margin-bottom:0 }
.np-own #np-ok{ margin-left:auto }

/* ── fields inside a dialogue ────────────────────────────────────────── */
/* 15px and 14px of padding is right for a full-page form and large inside a
   box. Same shapes, one step down, and the labels get room to breathe. */
.sys-drawer .fld{ gap:5px; margin-bottom:14px }
.sys-drawer .fld input,
.sys-drawer .fld select,
.sys-drawer .fld textarea{ font-size:13.5px; padding:10px 13px;
  border-radius:var(--r3) }
.sys-drawer .fld select{ padding-right:34px; background-position:right 12px center }
.sys-drawer .fld span{ font-size:11px; font-weight:800; letter-spacing:.1em;
  text-transform:uppercase; color:var(--text-2) }
.sys-drawer .fld span i{ font-style:normal; letter-spacing:0; font-weight:600;
  text-transform:none; opacity:.7; margin-left:5px }
.np-what .fld{ margin-bottom:8px }
/* The date picker's own button is the browser's, and it comes in the
   browser's blue-grey. It cannot be replaced without building a date picker,
   which is not a thing to build twice — so it is recoloured to belong. */
.sys-drawer .fld input[type=date]::-webkit-calendar-picker-indicator{
  opacity:.5; cursor:pointer;
  filter:sepia(1) saturate(.4) hue-rotate(-15deg) brightness(.7) }
.sys-drawer .fld input[type=date]::-webkit-calendar-picker-indicator:hover{
  opacity:.9 }

/* ═══════════════════════════════════════════════════════════════════════
   MONEY — SHAPED BY HOW THE BUSINESS GETS PAID

   Three pieces the Money overview needs and nothing else does. Money is the
   one screen whose figures change per business (a shop sees what came in, a
   plumber sees what has not been billed), so it is the one screen that
   needs a heading over a row of figures.
   ═══════════════════════════════════════════════════════════════════════ */

/* A business that is both — a tradie with a shopfront — gets two rows, and
   they must not read as one pile of money. */
.money-group + .money-group{ margin-top:var(--s5) }
.money-group h3{ font-size:var(--t-small); font-weight:var(--t-small-w);
  line-height:var(--t-small-lh); letter-spacing:.06em; text-transform:uppercase;
  color:var(--text-2); margin:0 0 var(--s2) }

/* Two lists on this screen say "who, how much, and what do I do about it".
   .kv could not carry the third: its label column is a fixed 40%, which is
   right for a field and wrong for a name with a button after it. */
.money-list{ display:flex; flex-direction:column }
.money-list .r{ display:flex; align-items:center; gap:var(--s3);
  padding:8px 0; border-bottom:1px solid var(--line-2) }
.money-list .r:last-child{ border-bottom:0 }
.money-list .n{ flex:1; min-width:0; font-size:12.5px; font-weight:600;
  color:var(--ink); overflow-wrap:anywhere }
.money-list .n i{ display:block; font-style:normal; font-weight:500;
  font-size:11.5px; color:var(--faint) }
.money-list > .r > b{ flex:none; font-size:13.5px; font-weight:700 }
.sys-b.thin{ flex:none; padding:4px var(--s3); font-size:11.5px;
  border-radius:99px; min-height:28px }
/* A thumb's size wherever a thumb might be: a coarse pointer, or a phone's
   width (a small laptop window with a mouse loses nothing by it). */
@media (pointer:coarse), (max-width:560px){ .sys-b.thin{ min-height:var(--tap); padding:0 15px } }

/* The liability card. Quieter than the figures above it, and it says why. */
.money-owed .sys-figs{ margin-top:var(--s3) }

/* A strip that knows its own width. Without this a three-figure row on a
   four-column grid ends in an empty grey box, because the dividers are the
   container's background showing through the gap. */
.money-group .sys-figs, .money-owed .sys-figs{
  grid-template-columns:repeat(min(var(--n, 2), 2), 1fr) }
@media (min-width:760px){
  .money-group .sys-figs, .money-owed .sys-figs{
    grid-template-columns:repeat(var(--n, 4), 1fr) } }
@media (max-width:759px){
  .sys-figs[data-odd] > .sys-fig:last-child{ grid-column:1 / -1 } }

/* ═══════════════════════════════════════════════════════════════════════
   THE DIARY

   Namespaced .dia-* on purpose. The week view used .week and .wday, and so
   does the old Home's "week ahead" 220 lines further down app.css — a later
   `display:flex; flex-direction:column` turned the seven-column grid into a
   vertical stack, one screen per day. Two features sharing a class name is
   the same bug as nav_slots vs V2_AREAS and .home-bar vs the ratio bar, and
   the fix is the same: one of them gets its own words.
   ═══════════════════════════════════════════════════════════════════════ */

.dia-bar{ display:flex; align-items:center; gap:var(--s4); flex-wrap:wrap;
  margin-bottom:var(--s3) }

/* The day's numbers as a line of text. */
.dia-glance{ display:flex; align-items:baseline; gap:7px; flex-wrap:wrap;
  font-size:12.5px; font-weight:600; color:var(--text-2);
  margin:0 0 var(--s3) }
.dia-glance b{ font-size:13.5px; font-weight:800; color:var(--ink);
  font-variant-numeric:tabular-nums }
.dia-glance i{ font-style:normal; color:var(--line); font-weight:700 }
.dia-nav{ display:flex; align-items:center; gap:6px; margin-left:auto }
.dia-nav .sys-b svg{ width:14px; height:14px }

/* The day's cards are a HEADER, and the calendar runs full width underneath.

   It was built side by side first — grid left, cards right — and side by side
   was wrong for the reason that is obvious once you see it: the calendar IS
   the screen, and anything beside it is competing for the width it needs. As
   a strip across the top the cards are read once on the way in, and then the
   day has the whole page. */
.dia-top{ display:grid; gap:var(--s3); margin-bottom:var(--s3);
  align-items:start; grid-template-columns:repeat(auto-fit, minmax(250px, 1fr)) }
.dia-top:empty{ display:none }
.dia-top .sys-card{ min-width:0; padding:var(--s3) var(--s4) }
.dia-top .sys-sect h2{ margin-bottom:var(--s1) }
.dia-top .dia-list .r{ padding:5px 0 }
.dia-top p.sys-dim{ margin:var(--s2) 0 0; font-size:11.5px; line-height:1.4 }

/* The calendar, and a slim rail for the one list with no ceiling.

   A waitlist only grows — every cancellation that does not get filled adds to
   it — so in the header strip it was either truncated to three, which throws
   away the ORDER that is the whole point of a waitlist, or it pushed the
   calendar off the screen. Down the side it can be as long as it is, with its
   own scroll, and a queue of names does not need 300px. */
.dia-day{ display:flex; align-items:flex-start; gap:var(--s3) }
.dia-main{ flex:1 1 auto; min-width:0 }
.dia-rail{ flex:0 0 248px; width:248px; display:flex; flex-direction:column;
  gap:var(--s3); position:sticky; top:var(--s3);
  max-height:calc(100vh - 140px); overflow-y:auto; overscroll-behavior:contain }
.dia-rail .sys-card{ padding:var(--s3) }
.dia-rail .dia-list .r{ padding:5px 0 }
.dia-rail p.sys-dim{ font-size:11px; line-height:1.4; margin:var(--s2) 0 0 }
.dia-rail .sys-sect h2{ margin-bottom:var(--s2) }
.dia-rail .dia-list .n{ font-size:12px }
.dia-rail .dia-list .n i{ font-size:11px }
/* Only the standalone button at the foot of a rail card goes full width. The
   row buttons are .thin and must not — one of them stretched to 180px of a
   264px rail and left the customer's name ten pixels to wrap into, one
   letter per line. */
.dia-rail .sys-b:not(.thin){ width:100% }
/* One line per person. A queue is read down, and a three-line row means
   ten people fill the screen where thirty should. */
.dia-rail .dia-list .r{ flex-wrap:nowrap; gap:var(--s2) }
.dia-rail .dia-list .n{ flex:1 1 auto; min-width:0; overflow-wrap:break-word }
.dia-rail .dia-list .q{ width:14px }
@media (max-width:900px){
  .dia-day{ display:block }
  .dia-rail{ width:100%; flex-basis:auto; margin-top:var(--s4);
    position:static; max-height:none } }

.dia-figs{ display:grid; grid-template-columns:repeat(2, 1fr); gap:1px;
  background:var(--line); border:1px solid var(--line);
  border-radius:var(--r3); overflow:hidden }
.dia-figs > .sys-fig:only-child{ grid-column:1 / -1 }

/* One list shape for every card in the side column: who, what, and the one
   button that does something about it. */
.dia-list{ display:flex; flex-direction:column }
.dia-list .r{ display:flex; align-items:center; gap:var(--s3);
  padding:8px 0; border-bottom:1px solid var(--line-2) }
.dia-list .r:last-child{ border-bottom:0 }
.dia-list .r[data-work]{ cursor:pointer }
.dia-list .r[data-work]:hover{ background:var(--cream) }
.dia-list .n{ flex:1; min-width:0; font-size:12.5px; font-weight:600;
  color:var(--ink); overflow-wrap:anywhere }
.dia-list .n i{ display:block; font-style:normal; font-weight:500;
  font-size:11.5px; color:var(--faint) }
.dia-list > .r > b{ flex:none; font-size:13px; font-weight:700 }
.dia-list .q{ flex:none; width:20px; font-size:11px; font-weight:800;
  color:var(--faint); font-variant-numeric:tabular-nums }
.dia-list .r.hot .n{ color:var(--ink) }

/* ── the week ────────────────────────────────────────────────────────── */
/* minmax(0, 1fr), not 1fr. A bare 1fr is minmax(auto, 1fr), so a day with a
   long customer name on a chip pushes its own column wider and the week comes
   out at 144px Monday and 246px Wednesday — seven columns that are supposed
   to be identical, sized by whoever happens to be booked in. */
.dia-week{ display:grid; grid-template-columns:repeat(7, minmax(0, 1fr));
  padding:0; overflow:hidden; min-width:700px }
.dia-wday{ border-left:1px solid var(--line-2); min-height:280px;
  display:flex; flex-direction:column; cursor:pointer }
.dia-wday:first-child{ border-left:0 }
.dia-wday:hover{ background:var(--cream) }
.dia-wday.now .dia-wh{ background:var(--ink); color:#fff }
.dia-wday.now .dia-wh i{ color:rgba(255,255,255,.7) }
.dia-wday.shut{ background:#FCFAF7 }
.dia-wh{ display:flex; align-items:baseline; gap:6px; padding:10px 11px;
  border-bottom:1px solid var(--line-2) }
.dia-wh b{ font-size:11px; font-weight:800; text-transform:uppercase;
  letter-spacing:.05em }
.dia-wh span{ font-size:15px; font-weight:800 }
.dia-wh i{ margin-left:auto; font-style:normal; font-size:10.5px;
  font-weight:700; color:var(--text-2); font-variant-numeric:tabular-nums }
.dia-wb{ display:flex; flex-direction:column; gap:5px; padding:8px }
.dia-wnone{ min-height:20px; font-size:11px; color:var(--faint);
  text-align:center; padding-top:8px }
/* The week scrolls sideways rather than squeezing seven days into a phone. */
.dia-main:has(> .dia-week){ overflow-x:auto; width:100% }

/* ── dragging ────────────────────────────────────────────────────────── */
.calbody.dragging{ cursor:grabbing; user-select:none }
.calbody.dragging .block{ transition:none }
.block.dragging{ z-index:5; box-shadow:0 10px 24px rgba(26,22,19,.18);
  opacity:.95; cursor:grabbing }
.col.over{ background-color:var(--cream) }
.block{ touch-action:none }

/* ── the booking dialogue ────────────────────────────────────────────── */
.bk{ display:grid; gap:var(--s5); grid-template-columns:1fr }
@media (min-width:720px){ .bk{ grid-template-columns:1fr 1fr } }
.bk-l, .bk-r{ display:flex; flex-direction:column; gap:var(--s4); min-width:0 }
.bk-when{ display:flex; align-items:baseline; gap:var(--s3); flex-wrap:wrap }
.bk-when b{ font-size:15px; font-weight:800 }
.bk-when span{ font-size:13px; color:var(--text-2); font-weight:600 }

.dia-kv{ display:grid; grid-template-columns:1fr 1fr; gap:var(--s3) }
.dia-kv > div{ min-width:0 }
.dia-kv .wide{ grid-column:1 / -1 }
.dia-kv span{ display:block; font-size:10px; font-weight:800;
  letter-spacing:.1em; text-transform:uppercase; color:var(--text-2) }
.dia-kv b{ font-size:13.5px; font-weight:700; overflow-wrap:anywhere }
.dia-kv a{ color:inherit }

.bk-items{ border-top:1px solid var(--line-2); padding-top:var(--s2) }
.bk-acts{ display:flex; gap:var(--s2); flex-wrap:wrap; margin-top:auto }
/* A chip cannot be wider than the day it is in. */
.dia-wb .wchip{ min-width:0; overflow-wrap:anywhere }
.dia-wb .wchip b, .dia-wb .wchip span{ overflow-wrap:anywhere }

/* ── dragging something into the day ─────────────────────────────────────
   The thing being dragged follows the pointer as a small label rather than
   the row itself moving: the row has to stay where it is, because the list
   it is in is the thing giving the drag its meaning. */
.dia-ghost{ position:fixed; top:0; left:0; z-index:60; pointer-events:none;
  padding:6px 11px; border-radius:99px; font-size:12px; font-weight:700;
  background:var(--ink); color:#fff; white-space:nowrap;
  box-shadow:0 8px 20px rgba(26,22,19,.22) }
.dia-ghost.on{ background:var(--orange-btn) }
.drop-me{ cursor:grab }
.drop-me.lifting{ opacity:.45 }
.dia-list .r.drop-me:active{ cursor:grabbing }

/* A checkbox in a dialogue. .sys-fl stacks a label above a control, which is
   wrong for a tickbox — the words belong beside it, and the whole line should
   be the target. */
.sys-fl.sys-check{ display:block }
.sys-fl.sys-check > span{ display:flex; align-items:center; gap:9px;
  cursor:pointer; font-size:13.5px; font-weight:600; color:var(--ink) }
.sys-fl.sys-check input{ width:16px; height:16px; flex:none; accent-color:var(--orange-btn) }
@media (pointer:coarse){ .sys-fl.sys-check > span{ min-height:var(--tap) } }

/* ═══════════════════════════════════════════════════════════════════════
   MODULES · the card look (2026-09-19)

   Everything here is scoped to `.mods`. `.ptile` is borrowed whole from
   Sell's till, and the till is a wall of small tappable things where a
   product is a name and a price. Modules is not that any more: a module
   needs an icon, a state, a sentence of what it does and an action, which
   is a card rather than a tile. Unscoped, these rules would redesign the
   point of sale by accident.

   The basket stays. The mockup this is built from has no basket and no
   prices, and adopting that literally would remove the one thing that
   stops somebody paying $70 for $59 of the same modules. So the look is
   the mockup's and the arithmetic underneath is unchanged.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── the band across the top ──────────────────────────────────────────── */
.mods .modhero{ background:var(--ink); border-radius:var(--r);
  padding:26px 28px; display:grid; grid-template-columns:1fr auto;
  gap:26px; align-items:center; margin-bottom:var(--s4) }
.mods .modhero .eyebrow{ font-size:11px; font-weight:800; letter-spacing:.16em;
  text-transform:uppercase; color:rgba(255,255,255,.45) }
.mods .modhero h1{ font-size:25px; font-weight:800; letter-spacing:-.035em;
  color:#fff; margin-top:10px; display:flex; align-items:center; gap:10px }
.mods .modhero h1::before{ content:""; width:9px; height:9px; border-radius:50%;
  background:var(--orange); flex:none }
.mods .modhero p{ font-size:14px; color:rgba(255,255,255,.66); font-weight:500;
  margin-top:6px; max-width:52ch }
.mods .hpoints{ display:flex; gap:22px }
.mods .hpoint{ max-width:15ch; padding-left:22px; border-left:1px solid rgba(255,255,255,.14) }
.mods .hpoint:first-child{ border-left:0; padding-left:0 }
.mods .hpoint i{ display:block; width:22px; height:22px; color:var(--orange);
  margin-bottom:9px }
.mods .hpoint i svg{ width:22px; height:22px; stroke-width:1.9 }
.mods .hpoint b{ display:block; font-size:13.5px; font-weight:800; color:#fff;
  letter-spacing:-.02em }
.mods .hpoint span{ display:block; font-size:12px; color:rgba(255,255,255,.55);
  font-weight:500; line-height:1.45; margin-top:3px }
@media (max-width:1100px){
  .mods .modhero{ grid-template-columns:1fr }
  .mods .hpoints{ flex-wrap:wrap; gap:18px }
}

/* ── filters, as pills ────────────────────────────────────────────────── */
.mods .cats{ display:flex; flex-wrap:wrap; gap:8px; padding:0 20px 4px }
.mods .cat{ border:1.5px solid var(--line); background:var(--white);
  border-radius:99px; padding:9px 16px; font-size:13px; font-weight:700;
  letter-spacing:-.01em; color:var(--mid); transition:.13s;
  display:inline-flex; align-items:center; gap:7px; min-height:auto }
.mods .cat:hover{ border-color:var(--faint); color:var(--ink) }
.mods .cat span{ font-size:12px; font-weight:800; color:var(--faint);
  font-variant-numeric:tabular-nums }
.mods .cat.on{ border-color:var(--orange); background:var(--orange-l);
  color:var(--orange-d) }
.mods .cat.on span{ color:var(--orange-d) }

/* ── a module, as a card ──────────────────────────────────────────────── */
.mods .pgrid{ grid-template-columns:repeat(auto-fill,minmax(310px,1fr));
  gap:var(--gap); padding:0 20px 20px }
/* Three rows, and the middle one takes the slack, so every card's action
   sits on the same line no matter how long the blurb is. Without this a
   two-line description pushes its own button down and the wall looks
   ragged. */
.mods .ptile{ display:grid; grid-template-columns:auto 1fr;
  grid-template-rows:auto 1fr auto; gap:4px 14px;
  align-items:start; text-align:left; background:var(--white);
  border:1.5px solid var(--line); border-radius:var(--r2); padding:18px;
  min-height:0; transition:.13s }
.mods .ptile:hover{ border-color:var(--faint); transform:translateY(-1px) }
.mods .picon{ grid-row:1/4; width:44px; height:44px; border-radius:14px;
  display:flex; align-items:center; justify-content:center; background:var(--lav);
  color:var(--lav-d) }
.mods .picon svg{ width:21px; height:21px }
.mods .ptile.i-mint .picon{ background:var(--mint); color:var(--mint-d) }
.mods .ptile.i-butter .picon{ background:var(--butter); color:var(--butter-d) }
.mods .ptile.i-peach .picon{ background:var(--peach); color:var(--peach-d) }
.mods .ptile.i-sky .picon{ background:var(--sky); color:var(--sky-d) }
.mods .phead{ display:flex; align-items:center; gap:9px; flex-wrap:wrap }
.mods .ptile b{ font-size:15.5px; font-weight:800; letter-spacing:-.025em;
  color:var(--ink) }
.mods .pdesc{ grid-column:2; font-size:13px; color:var(--text-2);
  font-weight:500; line-height:1.5; margin-top:2px }
.mods .pfoot{ grid-column:2; display:flex; align-items:center; gap:10px;
  margin-top:13px }
.mods .pfoot .pr{ margin-left:auto; font-size:13px; font-weight:700;
  color:var(--mid); text-align:right; line-height:1.3 }
.mods .pfoot .pr small{ font-size:11px; color:var(--faint); font-weight:600 }
/* The action never wraps. A two-line "Turn / on" is the single ugliest
   thing a card like this can do. */
.mods .pact{ white-space:nowrap; flex:none }
/* A long name and a long badge together are allowed to stack, but the name
   keeps the first line. */
.mods .phead b{ flex:1 1 auto; min-width:0 }
.mods .pchev{ color:var(--faint); font-size:15px; line-height:1 }

/* ── the badge that says where you stand with it ──────────────────────── */
.mods .pbadge{ font-size:11px; font-weight:800; letter-spacing:-.01em;
  padding:4px 9px; border-radius:99px; font-style:normal; white-space:nowrap }
.mods .b-inc{ background:var(--line-2); color:var(--text-2) }
.mods .b-act{ background:var(--mint); color:var(--mint-d2) }
.mods .b-avl{ background:var(--line-2); color:var(--text-2) }
.mods .b-soon{ background:transparent; color:var(--faint);
  border:1.5px solid var(--line) }

/* ── the action on the card ───────────────────────────────────────────── */
.mods .pact{ font-size:12.5px; font-weight:800; padding:7px 14px;
  border-radius:99px; background:var(--orange-l); color:var(--orange-d) }
.mods .pact.quiet{ background:var(--line-2); color:var(--text-2) }
.mods .ptile.on .pact{ background:var(--line-2); color:var(--text-2) }

/* States. `on` is a module already running; `picked` is one in the basket
   waiting to be paid for. Those are different facts and they looked the
   same before this. */
.mods .ptile.on{ background:var(--white); border-color:var(--mint) }
.mods .ptile.later{ opacity:.55 }
.mods .ptile.later:hover{ opacity:.8; transform:none }
.mods .ptile.picked{ background:var(--white); border-color:var(--orange);
  box-shadow:0 0 0 3px var(--orange-l) }
.mods .ptile.picked b{ color:var(--ink) }
.mods .ptile.picked .pact{ background:var(--orange); color:#fff }

/* The i is on the chevron's side of the card now, not floating over the
   corner of a small tile. */
.mods .tinfo{ position:static; margin-left:2px }

/* ── "your sidebar will update" ───────────────────────────────────────
   The question the mockup answers that the basket never did: where does
   this actually show up. Reads from nav_slots like everything else. */
.mods .sidepreview{ margin-top:var(--s4); padding-top:var(--s4);
  border-top:1px solid var(--line) }
.mods .sidepreview > b{ display:block; font-size:11px; font-weight:800;
  letter-spacing:.13em; text-transform:uppercase; color:var(--faint);
  margin-bottom:10px }
.mods .navmock{ background:var(--ink); border-radius:var(--r3); padding:10px 8px }
.mods .navmock i{ display:flex; align-items:center; gap:9px; padding:6px 9px;
  border-radius:8px; font-size:12.5px; font-weight:600; font-style:normal;
  color:rgba(255,255,255,.62) }
.mods .navmock i.new{ color:#fff; border:1.5px dashed var(--orange) }
.mods .navmock i svg{ width:15px; height:15px; flex:none }

@media (max-width:760px){
  .mods .pgrid{ grid-template-columns:1fr }
  .mods .modhero{ padding:20px }
  .mods .modhero h1{ font-size:21px }
}


/* ── the door out of Money's invoice list ─────────────────────────────────
   Two links, not a toolbar. `.tlink` and `.sys-foot` were reached for first
   and neither exists in this app — they are the marketing site's classes.
   `.linkish` is the one this app actually has. */
.docsfoot{ display:flex; flex-wrap:wrap; gap:8px 22px; padding:16px 0 4px;
  margin-top:10px; border-top:1px solid var(--line) }
.docsfoot .linkish{ background:none; border:0; padding:6px 0; cursor:pointer }

/* ═══════════════════════════════════════════════════════════════════════
   IMPORT — bring the file you already have

   The shape of the screen carries the argument: the upload is the big
   target, the template is a line of text underneath it, and the last step
   is a set of figures rather than a tick. §IMPORT.md
   ═══════════════════════════════════════════════════════════════════════ */

.imp-steps{ display:flex; gap:6px; list-style:none; margin:0 0 18px; padding:0;
  flex-wrap:wrap }
.imp-steps li{ display:flex; align-items:center; gap:7px; font-size:12.5px;
  font-weight:700; color:var(--faint); padding:6px 12px 6px 6px;
  border-radius:999px; background:var(--cream-2) }
.imp-steps li .n{ display:grid; place-items:center; width:20px; height:20px;
  border-radius:50%; background:var(--line); color:var(--text-2); font-size:11px }
.imp-steps li.on{ color:var(--ink); background:var(--orange-l) }
.imp-steps li.on .n{ background:var(--orange); color:#fff }
.imp-steps li.past{ color:var(--text-2) }
.imp-steps li.past .n{ background:var(--go, #cfe8d4); color:var(--ink) }

.imp-pick{ display:grid; gap:12px; grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  margin-bottom:18px }
.imp-card{ text-align:left; display:flex; flex-direction:column; gap:5px;
  padding:18px; border:1.5px solid var(--line); border-radius:16px;
  background:var(--white); cursor:pointer; transition:border-color .12s, transform .12s }
.imp-card:hover{ border-color:var(--orange); transform:translateY(-1px) }
.imp-card b{ font-size:16px }
.imp-card span{ font-size:13px; color:var(--text-2); line-height:1.45 }

/* The upload is the path. It should look like the path. */
.imp-drop{ display:flex; flex-direction:column; align-items:center; gap:8px;
  padding:38px 18px; border:2px dashed var(--line); border-radius:16px;
  text-align:center; transition:border-color .12s, background .12s }
.imp-drop.over{ border-color:var(--orange); background:var(--orange-l) }
.imp-drop b{ font-size:17px }
.imp-drop span{ font-size:13.5px; color:var(--text-2); max-width:42ch; line-height:1.5 }
.imp-drop button{ margin-top:6px }

.imp-map{ display:flex; flex-direction:column; gap:2px }
.imp-row{ display:grid; grid-template-columns:minmax(0,1fr) 220px minmax(0,1fr);
  gap:14px; align-items:center; padding:9px 4px;
  border-bottom:1px solid var(--line-2) }
.imp-row .f{ font-size:14px; font-weight:700 }
.imp-row .f i{ font-style:normal; font-size:11px; font-weight:800; color:var(--orange);
  text-transform:uppercase; letter-spacing:.06em; margin-left:5px }
.imp-row .f em{ display:block; font-style:normal; font-size:12px; font-weight:500;
  color:var(--faint); margin-top:2px }
.imp-row select{ font:inherit; font-size:13.5px; padding:7px 9px; border-radius:9px;
  border:1.5px solid var(--line); background:var(--white); width:100% }
.imp-row .eg{ font-family:var(--m); font-size:12.5px; color:var(--text-2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }

.imp-modes{ display:grid; gap:8px; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)) }
.imp-mode{ display:flex; flex-direction:column; gap:3px; padding:12px 14px;
  border:1.5px solid var(--line); border-radius:12px; cursor:pointer }
.imp-mode.on{ border-color:var(--orange); background:var(--orange-l) }
.imp-mode input{ position:absolute; opacity:0; pointer-events:none }
.imp-mode b{ font-size:14px }
.imp-mode span{ font-size:12.5px; color:var(--text-2); line-height:1.4 }

.imp-counts{ display:grid; gap:10px;
  grid-template-columns:repeat(auto-fit,minmax(130px,1fr)); margin-bottom:14px }
.imp-count{ padding:14px; border-radius:12px; background:var(--cream-2) }
.imp-count b{ display:block; font-family:var(--m); font-size:26px; letter-spacing:-.02em }
.imp-count span{ display:block; font-size:13px; font-weight:700; margin-top:1px }
.imp-count em{ display:block; font-style:normal; font-size:11.5px; color:var(--faint);
  margin-top:3px; line-height:1.35 }
.imp-count.warn b{ color:var(--attn) }

/* The answer to "did Noti import what I gave it", stated as a sentence. */
.imp-sum{ display:flex; flex-direction:column; gap:3px; padding:14px 16px;
  border-radius:12px; margin:4px 0 14px; border-left:3px solid var(--line) }
.imp-sum.go{ background:var(--cream-2); border-left-color:#3E8C57 }
.imp-sum.warn{ background:var(--attn-l); border-left-color:var(--attn) }
.imp-sum b{ font-size:15px }
.imp-sum span{ font-size:13px; color:var(--text-2); line-height:1.45 }

.imp-stock{ display:grid; gap:10px;
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); margin-bottom:12px }
.imp-stock div{ padding:12px 14px; border-radius:12px; background:var(--cream-2) }
.imp-stock span{ display:block; font-size:12px; color:var(--text-2) }
.imp-stock b{ display:block; font-family:var(--m); font-size:19px; margin-top:2px }
.imp-stock .warn b{ color:var(--attn) }

.imp-gate{ padding:14px 16px; border-radius:12px; display:flex;
  flex-direction:column; gap:3px }
.imp-gate.go{ background:var(--cream-2) }
.imp-gate.warn{ background:var(--attn-l) }
.imp-gate b{ font-size:14.5px }
.imp-gate span{ font-size:13px; color:var(--text-2); line-height:1.45 }

.imp-rejects{ display:flex; flex-direction:column; gap:2px; margin-bottom:12px }
.imp-reject{ display:grid; grid-template-columns:86px minmax(0,1fr); gap:14px;
  padding:10px 4px; border-bottom:1px solid var(--line-2); align-items:start }
.imp-reject .ln{ font-family:var(--m); font-size:12.5px; color:var(--faint) }
.imp-reject .bd b{ display:block; font-size:14px }
.imp-reject .bd span{ display:block; font-size:12.5px; color:var(--attn);
  margin-top:2px; line-height:1.45 }

/* The rows a corrections upload did not place. Quiet — this is usually not a
   mistake, it is somebody sending their whole corrected file back — but each
   one is named so nobody leaves thinking it imported. */
.imp-ignored{ margin:8px 0 0; padding:0 0 0 16px; list-style:disc }
.imp-ignored li{ font-size:12.5px; color:var(--text-2); line-height:1.6 }

@media (max-width:820px){
  .imp-row{ grid-template-columns:1fr; gap:6px }
  .imp-row .eg{ font-size:12px }
}

/* ── the Inbox: a conversation that reads like texting ──────────────────
   The owner's brief (25 Sep): like WhatsApp, on the desk and on the phone.
   Desk: the list and the open conversation side by side, one surface. Phone
   (≤860px): the list; a conversation opens over everything, tab bar
   included, with the reply box at the bottom under the thumb.

   Every class is ib-. The first thread borrowed .tl, .tm and .ch — a
   timeline, a 64px time column and a card header elsewhere in this app —
   and rendered blank. */
.ib{ display:grid; grid-template-columns:minmax(260px,340px) 1fr;
  height:calc(100dvh - 150px); min-height:420px;
  background:var(--white); border-radius:var(--r); overflow:hidden;
  box-shadow:0 0 0 1px var(--line-2) }
.ib-list{ overflow-y:auto; border-right:1px solid var(--line-2); padding:6px }
.ib-row{ display:flex; gap:12px; align-items:center; width:100%; min-height:64px;
  padding:10px; border:0; border-radius:14px; background:none; text-align:left;
  font:inherit; color:var(--ink); cursor:pointer }
.ib-row:hover{ background:var(--cream-2) }
.ib-row.on{ background:var(--cream) }
.ib-av{ flex:none; width:42px; height:42px; border-radius:50%;
  display:grid; place-items:center; background:var(--mint); color:var(--mint-d2);
  font-weight:800; font-size:14px; letter-spacing:.02em }
.ib-av.q{ background:var(--cream); color:var(--text-2) }
.ib-rm{ flex:1; min-width:0; display:flex; flex-direction:column; gap:3px }
.ib-rt, .ib-rs{ display:flex; align-items:center; gap:8px; min-width:0 }
.ib-rt b{ flex:1; min-width:0; font-size:14.5px; font-weight:700;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.ib-when{ flex:none; font-size:12px; color:var(--text-2); font-weight:600 }
.ib-last{ flex:1; min-width:0; font-size:13.5px; color:var(--text-2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.ib-last em{ font-style:normal; color:var(--attn); font-weight:700 }
.ib-row.unread .ib-rt b, .ib-row.unread .ib-last{ color:var(--ink); font-weight:800 }
.ib-row.unread .ib-when{ color:var(--mint-d2) }
.ib-n{ flex:none; min-width:21px; height:21px; padding:0 6px; border-radius:11px;
  background:var(--mint-d2); color:#fff; font-size:12px; font-weight:800;
  display:grid; place-items:center }
.ib-fail{ flex:none; width:21px; height:21px; border-radius:50%;
  background:var(--attn); color:#fff; font-size:12px; font-weight:800;
  display:grid; place-items:center }
.ib-empty{ padding:24px 16px; color:var(--text-2); font-size:14px; line-height:1.5 }

.ib-pane{ display:flex; flex-direction:column; min-width:0; min-height:0;
  background:var(--cream-2) }
.ib-none{ margin:auto; max-width:320px; padding:24px; text-align:center; color:var(--text-2) }
.ib-none svg{ width:34px; height:34px; stroke:currentColor; fill:none; stroke-width:1.6 }
.ib-none p{ margin:8px 0 0; font-weight:700; color:var(--ink) }
.ib-small{ font-size:12.5px; line-height:1.5; color:var(--text-2); font-weight:500 }
.ib-none .ib-small{ color:var(--text-2); font-weight:500 }
.ib-mid{ margin:auto; padding:24px; text-align:center }

.ib-head{ display:flex; align-items:center; gap:12px; padding:10px 14px;
  background:var(--white); border-bottom:1px solid var(--line-2) }
.ib-hn{ flex:1; min-width:0; display:flex; flex-direction:column }
.ib-hn b{ font-size:15.5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.ib-hn span{ font-size:12.5px; color:var(--text-2); font-weight:600;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.ib-call, .ib-back{ flex:none; width:var(--tap); height:var(--tap); border-radius:50%;
  display:grid; place-items:center; border:0; background:var(--cream); color:var(--ink);
  cursor:pointer }
.ib-back{ display:none }
/* A count on the selected tab: the tab goes ink and the chip kept its pale
   fill, so white-ish text sat on cream and read as a blank dot. */
.ranges .cat.on .chipn{ background:#fff; color:var(--ink) }
.ib-call svg, .ib-back svg, .ib-send svg{ width:20px; height:20px; stroke:currentColor;
  fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round }

.ib-msgs{ flex:1; min-height:0; overflow-y:auto; padding:14px 16px;
  display:flex; flex-direction:column; gap:6px; overscroll-behavior:contain }
.ib-day{ align-self:center; margin:10px 0 4px }
.ib-day span{ display:block; padding:4px 12px; border-radius:10px; background:var(--white);
  font-size:12px; font-weight:700; color:var(--text-2); box-shadow:0 0 0 1px var(--line-2) }
.ib-b{ max-width:min(76%,540px); padding:8px 12px 6px; border-radius:18px;
  display:flex; flex-direction:column; gap:2px; line-height:1.4; font-size:14.5px }
.ib-b.in{ align-self:flex-start; background:var(--white); color:var(--ink);
  border-bottom-left-radius:6px; box-shadow:0 0 0 1px var(--line-2) }
.ib-b.out{ align-self:flex-end; background:var(--ink); color:#fff; border-bottom-right-radius:6px }
.ib-b.bad{ background:#FBE4DC; color:var(--ink); box-shadow:inset 0 0 0 1.5px #D9743F }
.ib-txt{ white-space:pre-wrap; overflow-wrap:anywhere }
.ib-subj{ font-size:13.5px }
.ib-meta{ align-self:flex-end; font-size:11.5px; font-weight:600; opacity:.62 }
.ib-retry{ align-self:flex-end; min-height:36px; padding:0 12px; margin-top:4px;
  border:0; border-radius:10px; background:var(--orange-btn); color:#fff;
  font:inherit; font-size:13px; font-weight:700; cursor:pointer }

.ib-compose{ display:flex; align-items:flex-end; gap:8px; padding:10px 12px;
  background:var(--white); border-top:1px solid var(--line-2) }
.ib-compose textarea{ flex:1; min-height:var(--tap); max-height:140px; resize:none;
  padding:11px 16px; border-radius:22px; border:1.5px solid var(--line);
  background:var(--cream-2); font:inherit; font-size:16px; line-height:1.35; color:var(--ink) }
.ib-send{ flex:none; width:var(--tap); height:var(--tap); border-radius:50%; border:0;
  display:grid; place-items:center; background:var(--mint-d2); color:#fff; cursor:pointer }
.ib-send:disabled{ opacity:.5 }
.ib-note{ padding:14px 16px; background:var(--white); border-top:1px solid var(--line-2);
  font-size:13.5px; color:var(--text-2) }

.ib-who{ display:flex; flex-direction:column; gap:10px; padding:14px 16px;
  background:var(--white); border-top:1px solid var(--line-2) }
.ib-picks{ display:flex; flex-wrap:wrap; gap:8px }
.ib-pick, .ib-add{ min-height:var(--tap); padding:0 16px; border-radius:22px; border:0;
  font:inherit; font-size:14.5px; font-weight:700; cursor:pointer }
.ib-pick{ background:var(--mint); color:var(--mint-d2); max-width:100%;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.ib-add{ flex:none; background:var(--ink); color:#fff }
.ib-hint{ margin-left:6px; font-size:11.5px; font-weight:700; opacity:.7 }
.ib-pick.was{ background:var(--cream); color:var(--ink) }
.ib-new{ display:flex; gap:8px }
.ib-new input{ flex:1; min-width:0; min-height:var(--tap); padding:0 16px; border-radius:22px;
  border:1.5px solid var(--line); background:var(--cream-2); font:inherit; font-size:16px }

/* Phone and small tablet: the list is the page; a conversation is a screen
   of its own, over the tab bar, until the back arrow. */
@media (max-width:699px){
  .ib{ display:block; height:auto; min-height:0; background:none; box-shadow:none; border-radius:0 }
  .ib-list{ border-right:0; padding:0; background:var(--white); border-radius:var(--r2) }
  .ib-pane{ display:none }
  .ib-opened .ib-pane{ display:flex; position:fixed; inset:0; z-index:50;
    padding-top:env(safe-area-inset-top); padding-bottom:env(safe-area-inset-bottom);
    background:var(--cream-2) }
  .ib-back{ display:grid; background:none; margin-left:-8px }
  .ib-head{ padding:6px 10px }
  .ib-b{ max-width:84% }
}

/* ── before you finish ──────────────────────────────────────────────────
   A short list somebody reads in two seconds, not a form. What is done is
   quiet, what is missing is not, and every line that can be cleared carries
   the thing that clears it. */
.fin-list{display:flex;flex-direction:column;gap:8px;margin:2px 0 6px}
.fin{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:11px;
     background:var(--paper,#f4efe7);font-size:14px}
.fin .m{width:16px;text-align:center;font-weight:700;opacity:.7}
.fin span:nth-child(2){flex:1}
.fin.ok{opacity:.6}
.fin.ok .m{color:#4a8f5b}
.fin.must{background:#fbeee2;box-shadow:inset 0 0 0 1.5px #d9a25f}
.fin.warn .m{color:#c07a2e}
.fin .sys-b{margin-left:auto}

/* ── a note is a line in a log ──────────────────────────────────────────
   The box is at the top because writing one is the common act; reading them
   back happens underneath, newest first. */
.notewrite{display:flex;gap:8px;align-items:flex-start;margin-bottom:14px}
.notewrite textarea{flex:1;min-height:46px;resize:vertical;font:inherit;
  padding:10px 12px;border-radius:12px;border:1.5px solid var(--line,#e2d9cc);
  background:var(--card,#fff)}
.notelog{display:flex;flex-direction:column;gap:10px}
.noteline{padding:10px 12px;border-radius:12px;background:var(--paper,#f4efe7)}
.noteline .nb{white-space:pre-wrap;line-height:1.5}
.noteline .nm{font-size:12px;opacity:.6;margin-top:4px;display:flex;
              align-items:center;gap:8px}
.noteline .nm .mute{font-size:12px;padding:0;margin-left:auto}

/* ── what happens next ──────────────────────────────────────────────────
   Beside the notes and deliberately unlike them: a note is a paragraph you
   read, this is a line you finish. So the tick is the first thing on the
   row and the whole row is short enough to scan a stack of them. */
.nacts{display:flex;flex-direction:column;gap:2px}
.nact{display:flex;align-items:flex-start;gap:var(--s2);padding:7px var(--s2);
  border-radius:var(--r2)}
.nact:hover{background:var(--wash)}
.nact-tick{flex:none;width:20px;height:20px;margin-top:1px;padding:0;border:1.5px solid var(--line);
  border-radius:50%;background:none;cursor:pointer;display:grid;place-items:center;
  color:transparent;transition:border-color .12s,color .12s,background .12s}
.nact-tick svg{width:12px;height:12px}
.nact:hover .nact-tick{border-color:var(--ink)}
.nact-tick:hover{background:var(--ink);border-color:var(--ink);color:#fff}
.nact-say{min-width:0;display:flex;flex-direction:column;gap:1px}
.nact-say b{font-weight:600;line-height:1.35}
.nact-say span{font-size:.88em;opacity:.6;line-height:1.35}
.nact > i{margin-left:auto;font-style:normal;font-size:.82em;opacity:.55;
  white-space:nowrap;padding-top:2px}
/* Late is the one thing worth colouring: everything else here is a date. */
.nact.is-late > i{color:var(--peach-d);opacity:1;font-weight:600}
.nact-add{margin-top:var(--s2)}

/* ── picking a line ─────────────────────────────────────────────────────
   A list you tap, not a form you fill in. The price sits on the right of
   each row because that is the thing being compared when somebody is
   scanning for the right one. */
.linefind{width:100%;box-sizing:border-box;font:inherit;padding:11px 12px;
  border-radius:12px;border:1.5px solid var(--line,#e2d9cc);
  background:var(--card,#fff);margin-bottom:10px;min-height:46px}
.linelist{display:flex;flex-direction:column;gap:4px;max-height:44vh;
  overflow-y:auto;margin-bottom:14px}
.lineopt{display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  font:inherit;padding:12px 14px;border-radius:12px;cursor:pointer;
  border:1.5px solid transparent;background:var(--paper,#f4efe7)}
.lineopt span{flex:1;min-width:0}
.lineopt b{font-variant-numeric:tabular-nums;white-space:nowrap}
.lineopt:hover{border-color:var(--line,#e2d9cc);background:var(--card,#fff)}
.lineopt[hidden]{display:none}
.sys-b.wide{width:100%;justify-content:center}

/* ── what they had last time ────────────────────────────────────────────
   Above the empty boxes, quiet enough to be reference rather than an
   instruction. A stylist reads it and then types this visit's; they are not
   editing last time's. */
.lasttime{background:var(--paper,#f4efe7);border-radius:12px;padding:12px 14px;
          margin-bottom:16px}
.lt-h{font-size:11px;letter-spacing:.06em;text-transform:uppercase;
      opacity:.55;margin-bottom:7px}
.lt-row{display:flex;justify-content:space-between;gap:14px;padding:3px 0;
        font-size:14px}
.lt-row span{opacity:.7}
.lt-row b{text-align:right;word-break:break-word}
.lt-b{font-size:12px;opacity:.5;margin-top:7px}

/* `.q` in app.css is a global selectable-row class — flex, padding, a border
   and a radius. Using it for an amount put every figure on a job in its own
   little box with a gulf of empty row beside it. A scoped name instead.

   The lesson is smaller than the bug: a two-letter class in a shared
   stylesheet belongs to whoever defined it first. */

/* What the customer said when they booked. Read-only, and marked as theirs
   rather than as a task — it is the one row on this list nobody has to do
   anything about. */
.jf.said{background:var(--paper,#f4efe7);border-style:solid;
         border-color:transparent}
.jf.said .n b::before{content:'“ ';opacity:.4}

/* ── a job record ───────────────────────────────────────────────────────
   One record on the left, context on the right.

   The left is a SINGLE card whose parts are divided by a rule. Six cards
   sitting beside each other is what made this read as an admin screen: a
   card says "separate thing", and a job is not six separate things.

   The right is not carded at all — a rule and a small heading — so it reads
   as the detail around the job rather than four more products beside it. */
.jobgrid{display:grid;gap:var(--s4);align-items:start}
.jobcol{display:flex;flex-direction:column;min-width:0}
.jobgrid--one{grid-template-columns:1fr !important}

@media (min-width:1100px){
  .jobgrid{grid-template-columns:minmax(0,1.85fr) minmax(0,1fr);
           gap:var(--s4) var(--s6)}
}
/* One column — a phone, a tablet, a narrow window, or somebody who chose one:
   the columns dissolve and every part takes its place in the one frozen
   order (work.js ONE_ORDER: about, checklists, work, money, next, history), whoever is looking. */
.jobpart{min-width:0}
.jobgrid--one{display:flex;flex-direction:column;align-items:stretch}
.jobgrid--one > .jobcol{display:contents}
.jobgrid--one .jobpart{order:var(--o)}
@media (max-width:1099px){
  .jobgrid{display:flex;flex-direction:column;align-items:stretch}
  .jobgrid > .jobcol{display:contents}
  .jobgrid .jobpart{order:var(--o)}
}

.record{padding:0}
.record .part{padding:var(--s5)}
.record .part + .part{border-top:1px solid var(--line)}
.record .part > h3{font-size:12px;letter-spacing:.06em;text-transform:uppercase;
  opacity:.5;font-weight:700;margin:0 0 var(--s3)}
.jdesc{font-size:15.5px;line-height:1.55;margin:0;padding:var(--s5) var(--s5) 0}

/* what was done */
.wlines{display:flex;flex-direction:column}
.wline{display:grid;grid-template-columns:1fr auto 20px;align-items:baseline;
  gap:var(--s3);padding:10px 0;border-bottom:1px solid var(--line)}
.wline:last-child{border-bottom:0}
.wline .n{display:flex;flex-direction:column;gap:2px;min-width:0;font-weight:600}
.wline .n i{font-style:normal;font-weight:500;font-size:12.5px;opacity:.55}
.wline .a{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}
.wline .mute{padding:0;font-size:15px;line-height:1;opacity:0}
.wline:hover .mute{opacity:.5}

.facts{display:flex;flex-direction:column;gap:2px}
/* `space-between` with a right-aligned value throws the pair to opposite
   ends of whatever width it is given, which on the job sheet put "Type" and
   "Job" five hundred pixels apart. Same cause as `.kv`'s percentage label,
   same fix: cap the label, let the value sit beside it. */
.fact{display:flex;align-items:baseline;
  gap:var(--s4);padding:5px 0;font-size:14px}
.fact > span{opacity:.55;width:min(40%, 190px);flex:none}
.fact > b{font-weight:600;min-width:0;overflow-wrap:anywhere}
.facts.small{border-top:1px solid var(--line);margin-top:var(--s3);padding-top:var(--s3)}

/* money — a figure, not a banner. The orange slab across the full width
   read as an alert; money owed is not an error. The chip carries the
   urgency and the amount is just an amount. */
.invline{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 6px;font-size:14px}
.invline .linkish{font:inherit;font-weight:600}
.owe{margin:0;font-size:24px;font-weight:800;font-variant-numeric:tabular-nums}
.owe.paid{opacity:.6;font-weight:700}
.donesay{margin:0;font-size:14px;opacity:.7}
.jacts{display:flex;flex-wrap:wrap;gap:8px;margin-top:var(--s4)}

/* ── the context column ─────────────────────────────────────────────── */
.sidesec{padding:0 0 var(--s5)}
/* Each part is wrapped (work.js .jobpart), so a rule between neighbours is
   drawn on the wrapper's child rather than on sibling .sidesecs. */
.jobpart + .jobpart > .sidesec{border-top:1px solid var(--line);padding-top:var(--s5)}
.jobcol--main{gap:var(--s4)}
.sidesec .sys-sect{padding:0}
.sidesec .sys-sect > h2{font-size:12px;letter-spacing:.06em;text-transform:uppercase;
  opacity:.5;margin:0 0 var(--s3);font-weight:700}

.custname{font:inherit;font-size:17px;font-weight:700;background:none;border:0;
  padding:0;cursor:pointer;text-align:left}
.custway{font-size:14px;opacity:.7;margin-top:2px}
.custacts{display:flex;flex-wrap:wrap;gap:6px;margin-top:var(--s3)}
.custacts .sys-b{text-decoration:none}

/* ── the job page, presentation (29 Sep) ──────────────────────────────────
   Puts back the rule written above - on two columns the left is ONE card, the
   right is not carded - which the page had drifted from (a card and four bare
   sections on the left, three cards on the right). On one column (phone,
   tablet, narrow window) there are no boxes at all: plain sections divided by
   a rule. Hierarchy from type and space, not from boxes or colour. */

/* where it is and what it is, under the header */
.jobbrief{display:flex;flex-direction:column;gap:4px;margin:0 0 var(--s4);max-width:70ch}
.jobbrief .where{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap;align-self:flex-start;
  min-height:36px;color:var(--ink);text-decoration:none;font-size:15px}
.jobbrief .where svg{width:16px;height:16px;flex:none;color:var(--orange)}
.jobbrief .where b{font-weight:600}
.jobbrief .where span{font-size:13px;font-weight:700;color:var(--grey)}
.jobbrief .where:hover span{color:var(--ink)}
.jobbrief .what{margin:0;font-size:15px;line-height:1.55;color:var(--mid)}

/* an empty section: one line and its button */
.jobempty{display:flex;align-items:center;justify-content:space-between;
  gap:var(--s2) var(--s3);flex-wrap:wrap}
.jobempty > p{margin:0;flex:1 1 220px}

/* flat by default - every part a plain section, a rule between them */
.jobgrid .sys-card.record{background:none;border:0;border-radius:0;padding:0}
.jobgrid .record .part{padding:0}
.jobgrid .record .part + .part{border-top:1px solid var(--line);margin-top:var(--s5);padding-top:var(--s5)}
.jobgrid .sidesec{padding:0}
.jobgrid .jobpart + .jobpart > .sidesec{border-top:0;padding-top:0}
.jobgrid .jobpart{padding:var(--s5) 0}
.jobgrid .jobpart:not(.is-first){border-top:1px solid var(--line)}
.jobgrid .jobpart.is-first{padding-top:var(--s2)}
.jobgrid .jobcol--main{gap:0}
/* every section label the same size - "What we are doing" was the one
   heading at page size, competing with the job's own name */
.jobgrid .jobpart > .sys-sect > h2{font-size:12px;letter-spacing:.06em;text-transform:uppercase;
  opacity:.5;margin:0 0 var(--s3);font-weight:700}

@media (min-width:1100px){
  .jobgrid:not(.jobgrid--one) .jobcol > .jobpart:first-child{border-top:0}
  .jobgrid:not(.jobgrid--one) .jobcol--main{background:var(--white);border:1px solid var(--line);
    border-radius:var(--r3);padding:0 var(--s5)}
  .jobgrid:not(.jobgrid--one) .jobcol--main > .jobpart:first-child{padding-top:var(--s5)}
}

/* money: the figure, what it is part of, and the arithmetic when asked */
.owesub{margin:2px 0 0;font-size:13.5px;color:var(--grey);font-variant-numeric:tabular-nums}
.moneywhy{margin-top:var(--s2)}
.moneywhy > summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;
  min-height:36px;font-size:13px;font-weight:700;color:var(--grey)}
.moneywhy > summary::-webkit-details-marker{display:none}
.moneywhy > summary::after{content:'+';margin-left:6px;font-weight:600}
.moneywhy[open] > summary::after{content:'\2212'}
.moneywhy .facts.small{border-top:0;margin-top:0;padding-top:0}

/* somebody's number reads like the rest of the page, not a browser link */
.wholine > a{color:var(--ink);text-decoration:none;font-weight:600;opacity:1;
  font-variant-numeric:tabular-nums}

/* the one action, where the thumb is - phones only; the header's copy goes */
.jobdock{display:none}
@media (max-width:699px){
  .sys-page:has(.jobdock) .sys-head .acts > .sys-b.primary{display:none}
  .jobdock{display:block;position:sticky;z-index:30;
    bottom:calc(68px + env(safe-area-inset-bottom));
    margin:var(--s4) 0 0;padding:var(--s2) 0;background:var(--cream);
    border-top:1px solid var(--line)}
  .jobdock .sys-b{width:100%;min-height:48px;font-size:16px;justify-content:center}
  /* With the primary moved to the dock, the ··· menu sat alone on a row of
     its own under the title - it goes beside the title instead. */
  .sys-page:has(.jobdock) .sys-head{position:relative}
  .sys-page:has(.jobdock) .sys-head .t{padding-right:56px}
  .sys-page:has(.jobdock) .sys-head .acts{position:absolute;top:0;right:0;margin:0}
  .jobempty .sys-b{min-height:44px}
  .moneywhy > summary{min-height:44px}
}

/* ── the job page in six groups (owner, 29 Sep) ──────────────────────────
   A group heading says which stage of the job this is; the sections inside
   keep their small uppercase labels as sub-parts. */
.jgroup{display:flex;flex-direction:column;gap:var(--s5);min-width:0}
.jgroup-h{margin:0;font-size:18px;font-weight:800;letter-spacing:-.015em;color:var(--ink);line-height:1.25}
:is(.jgroup, .jgroup-in) > .sidesec, :is(.jgroup, .jgroup-in) > .sys-card, :is(.jgroup, .jgroup-in) > .sys-sect{margin:0;padding:0;border:0}
:is(.jgroup, .jgroup-in) > .sys-sect > h2{font-size:12px;letter-spacing:.06em;text-transform:uppercase;
  opacity:.5;margin:0 0 var(--s3);font-weight:700}
details.jgroup > summary{list-style:none;cursor:pointer;display:flex;align-items:center;min-height:36px}
details.jgroup > summary::-webkit-details-marker{display:none}
details.jgroup > summary::after{content:'+';margin-left:10px;font-weight:600;color:var(--grey)}
details.jgroup[open] > summary::after{content:'\2212'}
details.jgroup:not([open]){gap:0}
/* A group holding one section: its label would only repeat the group's
   ("Checklists" over "FORMS AND CHECKLISTS"). */
.jgroup[data-g="before"] > .sidesec > .sys-sect > h2,
.jgroup[data-g="next"] > .sidesec > .sys-sect > h2,
.jgroup[data-g="next"] > .jgroup-in > .sidesec > .sys-sect > h2{display:none}
@media (max-width:699px){ details.jgroup > summary{min-height:44px} }

/* ── the job page, second pass: the story of the job (owner, 29 Sep) ───────
   A workspace on the left with no box around it; the money and what is next
   in a rail on the right that stays in view while the work scrolls; job
   details and history folded at the foot, full width. */
.jobbrief .where{display:flex;align-items:center;gap:8px;margin:0;font-size:15px;font-weight:600;color:var(--ink)}
.jobbrief .where span{font-size:15px;font-weight:600;color:var(--ink)}   /* the address, not the old grey Directions label */
.jobways{display:flex;flex-wrap:wrap;gap:6px;margin-top:var(--s2)}
.jobways .sys-b{text-decoration:none}
.jobhidden{margin:var(--s1) 0 0;font-size:13px}
.jwait{margin:0;padding:10px 12px;border-radius:var(--r3);background:var(--butter);color:var(--butter-d);font-size:14.5px}
.jwait b{font-weight:800;margin-right:6px}

@media (min-width:1100px){
  .jobgrid--rail:not(.jobgrid--one){grid-template-columns:minmax(0,1fr) minmax(300px,33%)}
  .jobgrid--rail:not(.jobgrid--one) .jobcol--main{background:none;border:0;border-radius:0;padding:0}
  .jobgrid--rail:not(.jobgrid--one) .jobcol--main > .jobpart:first-child{padding-top:var(--s2)}
  .jobgrid--rail:not(.jobgrid--one) .jobcol--side{position:sticky;top:14px;align-self:start;
    background:var(--white);border:1px solid var(--line);
    border-radius:var(--r3);padding:0 var(--s5)}
  .jobgrid--rail:not(.jobgrid--one) .jobcol--side .jgroup-h{font-size:16px}
}

.jobfoot{margin-top:var(--s5);border-top:1px solid var(--line)}
.jobfoot .jfold{padding:var(--s3) 0;border-bottom:1px solid var(--line);gap:var(--s4)}
.jobfoot .jfold > summary{font-size:15px;font-weight:700}
.jobfoot .jfold[open]{padding-bottom:var(--s5)}

/* ── the job page, clarity pass (owner, 29 Sep) ───────────────────────────
   It had gone faint: cream, pale grey body text, pale rules - calm, but the
   eye could not tell the job from its metadata. Strong heading -> readable
   body -> genuinely secondary metadata; still restrained colour. */
.jobgrid, .jobfoot, .jobbrief{--job-rule:#DED5C8}
.jobgrid .sys-dim, .jobfoot .sys-dim, .jobbrief .sys-dim{color:var(--mid);opacity:1}
.jobbrief .what{color:var(--ink)}
.sys-page:has(.jobgrid) .sys-head .sys-sub{color:var(--mid)}
.jgroup-h{font-size:19px;font-weight:800;color:var(--ink)}
/* sub-labels: sentence case, darker, not a row of pale capitals */
.jgroup .sidesec .sys-sect > h2, :is(.jgroup, .jgroup-in) > .sys-sect > h2, .jgroup .record .part > h3{
  text-transform:none;letter-spacing:0;font-size:14px;font-weight:700;opacity:1;color:var(--mid);margin-bottom:var(--s2)}
.jgroup .fact > span{opacity:1;color:var(--mid)}
.jgroup .fact > b, .jgroup .wline .n, .jgroup .nb, .jgroup .frow .n{color:var(--ink)}
.jgroup .wline .n i, .jgroup .frow .n i, .noteline .nm{color:var(--mid);opacity:1}
.jgroup .wline{border-bottom-color:var(--job-rule)}
.jobgrid .jobpart:not(.is-first){border-top-color:var(--job-rule)}
.jobfoot, .jobfoot .jfold{border-color:var(--job-rule)}
.owesub, .moneywhy > summary{color:var(--mid)}
.jgroup .fstage-h{opacity:1;color:var(--mid)}
.jgroup .toldrow > span{opacity:1;color:var(--mid)}
.jgroup .toldrow{border-bottom-color:var(--job-rule)}
/* the manage sheet */
.fmlist{display:flex;flex-direction:column;gap:2px;margin-bottom:var(--s3)}
.fmrow{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);padding:10px 0;border-bottom:1px solid var(--line)}
.fmrow span{display:flex;flex-direction:column;gap:2px}
.fmrow i{font-style:normal;font-size:13px;color:var(--mid)}
.fmnote{margin:0 0 var(--s3)}

/* ── the job page, contrast step two + the Job block (owner, 29 Sep) ───────
   Still read as soft: 400-weight grey on cream. Primary text is ink and a
   touch heavier; secondary is a darker warm grey; section labels are small
   normal-case headings in ink, not pale capitals; rules are firmer. */
.jobgrid, .jobfoot, .jobbrief{--job-rule:#D3C8B9;--job-2:#4A423B}
.jobgrid .sys-dim, .jobfoot .sys-dim, .jobbrief .sys-dim, .sys-page:has(.jobgrid) .sys-head .sys-sub{color:var(--job-2)}
.jgroup .sidesec .sys-sect > h2, :is(.jgroup, .jgroup-in) > .sys-sect > h2, .jgroup .record .part > h3{color:var(--ink);font-size:15px;font-weight:700}
.jgroup .fact{font-size:15px}
.jgroup .fact > span, .jgroup .toldrow > span, .jgroup .fstage-h, .owesub, .moneywhy > summary,
.jgroup .wline .n i, .jgroup .frow .n i, .noteline .nm{color:var(--job-2)}
.jgroup .fact > b, .jgroup .toldrow > b{color:var(--ink);font-weight:600}
.jgroup .nb{color:var(--ink);font-weight:500}
.jgroup .wline .n{font-weight:600}
/* the job's purpose - the first substantive thing on the page */
.jscope{margin:0;font-size:17px;line-height:1.55;font-weight:500;color:var(--ink);max-width:70ch}

/* a charge line opens to change how many / the price each */
.wline-edit{background:none;border:0;padding:0;font:inherit;color:inherit;text-align:left;cursor:pointer}
.wline-edit:hover b, .wline-edit:hover{color:var(--orange-d)}
@media (max-width:699px){ .wline-edit{min-height:44px;justify-content:center} }
.lineqty{display:flex;align-items:center;gap:var(--s3);margin-bottom:var(--s3)}
.lineqty label{font-size:14px;font-weight:700}
.lineqty input{width:96px;min-height:44px;border:1.5px solid var(--line);border-radius:12px;padding:0 12px;font:inherit;font-size:16px}

/* notes and photos: a gallery, not a list of file names */
.gadd{margin-top:var(--s2)}
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:8px;margin-top:var(--s3)}
.gtile{position:relative;aspect-ratio:1;border-radius:var(--r3);overflow:hidden;padding:0;cursor:pointer;
  border:1px solid var(--line);background:var(--cream-2);font:inherit;color:inherit;display:block}
.gtile img{width:100%;height:100%;object-fit:cover;display:block;color:transparent}   /* no alt text flashing while it signs */
.gtile.is-doc{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;padding:8px;background:var(--white)}
.gdoc{display:flex;flex-direction:column;align-items:center;gap:4px;color:var(--grey)}
.gdoc svg{width:22px;height:22px}
.gdoc b{font-size:11px;font-weight:800;letter-spacing:.06em;color:var(--ink)}
.gcap{font-size:11.5px;line-height:1.3;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--mid)}
.gtag{position:absolute;left:6px;bottom:6px;font-style:normal;font-size:10.5px;font-weight:700;
  padding:2px 6px;border-radius:99px;background:var(--ink);color:#fff;opacity:.85}

/* forms — the STAGE is what distinguishes them, not the card around them.
   The same form at two stages used to be two identical boxes. */
.fstage + .fstage{margin-top:var(--s4)}
.fstage-h{font-size:12px;font-weight:700;opacity:.45;margin-bottom:4px}
.frow{display:grid;grid-template-columns:18px 1fr auto;align-items:baseline;
  gap:8px;width:100%;text-align:left;font:inherit;background:none;border:0;
  padding:7px 6px 7px 0;cursor:pointer;border-radius:8px}
.frow:hover{background:var(--cream-2)}
.frow .m{font-weight:700;opacity:.45}
.frow.done .m{color:#17633C;opacity:1}
.frow.must .m{color:#A8620F;opacity:1}
.frow .n{display:flex;flex-direction:column;gap:1px;min-width:0;font-weight:600}
.frow .n i{font-style:normal;font-weight:500;font-size:12.5px;opacity:.55}
.frow.done .n{font-weight:500;opacity:.75}

/* An extra nobody has answered: a question, so it looks like one. */
.asks{display:flex;flex-direction:column;gap:6px;margin-top:var(--s3)}
.ask{display:grid;grid-template-columns:1fr auto auto 20px;align-items:center;
  gap:10px;padding:9px 12px;border-radius:11px;background:var(--cream-2);
  box-shadow:inset 0 0 0 1.5px #E4C79B}
.ask .n{display:flex;flex-direction:column;gap:1px;min-width:0;font-weight:600;
  font-size:14px}
.ask .n i{font-style:normal;font-weight:500;font-size:12.5px;opacity:.6}
.ask .a{font-variant-numeric:tabular-nums;font-weight:700;white-space:nowrap}
.ask .mute{padding:0;font-size:15px;line-height:1;opacity:.45}

/* ── the job record, read rather than inferred ──────────────────────────
   Density comes from small quiet labels and short rows, not from cramming.
   A label at .55 opacity next to a 600-weight value is legible at six
   facts per inch; the same two things in a box with a heading are not. */
.fact.then{margin-top:-2px}
.fact.then > span{opacity:.4}

/* What the customer told us. The question is the quiet half — somebody
   scanning this is looking for the answers. */
.told{display:flex;flex-direction:column;gap:2px}
.toldrow{display:flex;align-items:baseline;justify-content:space-between;
  gap:var(--s4);padding:3px 0;border-bottom:1px solid var(--line)}
.toldrow:last-child{border-bottom:0}
.toldrow > span{opacity:.55;flex:0 1 auto}
.toldrow > b{font-weight:600;text-align:right;overflow-wrap:anywhere}
.toldfiles{display:flex;flex-wrap:wrap;gap:var(--s2);margin-top:var(--s3)}
.toldfile{display:flex;align-items:center;gap:6px;font-size:.85em;opacity:.7}
.toldfile svg{width:14px;height:14px}
.asked{font-size:.82em;align-self:center}

/* Everybody else on the account — the one you ring from the footpath. */
.whoelse{margin-top:var(--s3);border-top:1px solid var(--line);padding-top:var(--s3);
  display:flex;flex-direction:column;gap:var(--s2)}
.wholine{display:flex;align-items:baseline;gap:var(--s2);flex-wrap:wrap;font-size:.9em}
.wholine > b{font-weight:600}
.wholine > span{opacity:.55}
.wholine > a{margin-left:auto;opacity:.8}
.custway.quiet{opacity:.5;font-size:.85em;margin-top:var(--s2)}

/* What else the job is attached to. */
.links{display:flex;flex-direction:column;gap:1px}
.linkrow{display:flex;align-items:center;gap:var(--s2);width:100%;text-align:left;
  padding:7px var(--s2);border:0;border-radius:var(--r2);background:none;
  font:inherit;color:inherit}
button.linkrow{cursor:pointer}
button.linkrow:hover{background:var(--wash)}
.linkrow.flat{cursor:default}
.linkrow svg{width:15px;height:15px;opacity:.45;flex:none}
.linkrow > b{font-weight:600}
.linkrow > span{margin-left:auto;opacity:.55;font-size:.88em;white-space:nowrap}

/* What we used, and the evidence for it. */
.pilelab{font-size:.78em;letter-spacing:.04em;text-transform:uppercase;
  opacity:.45;margin:var(--s3) 0 var(--s2)}
.pilelab:first-child{margin-top:0}
.pile{display:flex;flex-direction:column;gap:1px}
.shot{display:flex;align-items:center;gap:var(--s2);padding:6px var(--s2);
  border-radius:var(--r2);font-size:.9em}
.shot svg{width:15px;height:15px;opacity:.4;flex:none}
.shot > span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.shot > i{margin-left:auto;font-style:normal;opacity:.5;font-size:.88em;white-space:nowrap}
/* A file opens, so the row is a button and says so. The list was plain text
   until 20 September for an honest reason — nothing could sign a URL — and
   a row that looks pressable and is not is worse than one that does not. */
button.shot{width:100%;text-align:left;border:0;background:none;font:inherit;
  color:inherit;cursor:pointer}
button.shot:hover{background:var(--wash)}
.pileadd{margin-top:var(--s2)}

/* The viewer. A picture fills the width it is given; anything else is a name
   and a way out to the browser, which is where a PDF is readable. */
.filepeek img{display:block;width:100%;height:auto;border-radius:var(--r2)}
.filenone{display:flex;align-items:center;gap:var(--s2);padding:var(--s4);
  border-radius:var(--r2);background:var(--wash)}
.filenone svg{width:22px;height:22px;opacity:.45;flex:none}
.filego{display:flex;gap:var(--s2);align-items:center;margin-top:var(--s3)}
/* `.mute` has no base rule anywhere — every use of it is scoped to the block
   it sits in, so an unscoped one is a default grey browser button. This is
   that scope, matching the Delete on a note. */
.filego .mute{margin-left:auto;background:none;border:0;padding:0;font:inherit;
  font-size:12px;color:var(--peach-d);cursor:pointer}
.filego .mute:hover{text-decoration:underline}

/* ── fill openings ──────────────────────────────────────────────────────
   Three counts, and the one that matters most is the one most software
   hides: who was left out. It gets the same weight as the others rather
   than a footnote, because a business that cannot see it concludes the
   thing is broken. */
.fo-form{display:flex;flex-direction:column;gap:var(--s3)}
.fo-form label{display:flex;flex-direction:column;gap:4px;font-size:13px;
  font-weight:600;color:var(--text-2)}
.fo-form input,.fo-form select,.fo-form textarea{font:inherit;font-size:15px;
  font-weight:500;color:var(--ink);padding:9px 12px;border:1.5px solid var(--line);
  border-radius:var(--r2);background:var(--white)}
.fo-form input:focus,.fo-form select:focus,.fo-form textarea:focus{outline:0;
  border-color:var(--orange)}
.fo-two{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3)}

.fo-when{font-size:15px;margin-bottom:var(--s3)}
.fo-counts{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s2);
  margin-bottom:var(--s3)}
.fo-counts > div{padding:var(--s3);border-radius:var(--r2);background:var(--wash);
  text-align:center}
.fo-counts b{display:block;font-size:24px;line-height:1.1}
.fo-counts span{font-size:11.5px;opacity:.65;line-height:1.25;display:block;margin-top:3px}
.fo-counts .ok{background:var(--mint,#D6EEDD)}
.fo-counts .out{background:var(--peach,#FBDDD0)}

.fo-none{padding:var(--s4);border-radius:var(--r2);background:var(--wash)}
.fo-none b{display:block;margin-bottom:6px}
.fo-none p{margin:0 0 8px;line-height:1.45}
.fo-who{margin-bottom:var(--s3)}
.fo-who summary{cursor:pointer;font-size:13px;font-weight:600;color:var(--text-2)}
.fo-list{margin-top:var(--s2);max-height:220px;overflow:auto}
.fo-row{display:flex;align-items:baseline;gap:var(--s2);padding:5px 0;font-size:14px}
.fo-row i{font-style:normal;opacity:.55;font-size:.86em}
.fo-row em{margin-left:auto;font-style:normal;font-size:.8em;color:var(--peach-d);
  font-weight:600}
.fo-row.is-out span{opacity:.5}
.fo-say{margin-top:var(--s3);padding:var(--s3);border-radius:var(--r2);
  background:var(--wash)}
.fo-say span{font-size:11.5px;text-transform:uppercase;letter-spacing:.04em;opacity:.5}
.fo-say p{margin:4px 0 0;line-height:1.45}
.fo-results{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--s2)}
.fo-results > div{padding:var(--s3);border-radius:var(--r2);background:var(--wash)}
.fo-results b{display:block;font-size:24px;line-height:1.1}
.fo-results span{font-size:12px;opacity:.65}

.fo-couldnot{margin:var(--s3) 0 0;padding:var(--s3);border-radius:var(--r2);
  background:var(--wash);font-size:13.5px;line-height:1.45}

/* ── the pieces of work on a job ────────────────────────────────────────
   Rows, not cards. A one-unit job must not look like enterprise software
   and a nine-unit job has to be readable at a glance: a mark, the thing,
   who has it, and only the counts that exist. */
.wunits{display:flex;flex-direction:column;gap:1px;margin-bottom:var(--s2)}
.wunit{display:flex;align-items:flex-start;gap:var(--s2);padding:7px var(--s2);
  border-radius:var(--r2)}
.wunit:hover{background:var(--wash)}
.wunit-mark{flex:none;width:22px;height:22px;padding:0;border:0;background:none;
  cursor:pointer;font-size:15px;line-height:1;color:var(--grey);
  display:grid;place-items:center;border-radius:50%}
.wunit-mark:hover{background:var(--ink);color:#fff}
.wunit-say{min-width:0;display:flex;flex-direction:column;gap:1px}
.wunit-say b{font-weight:600;line-height:1.35}
.wunit-say span{font-size:.86em;opacity:.6;line-height:1.35}
.wunit > i{margin-left:auto;font-style:normal;font-size:.82em;opacity:.55;
  white-space:nowrap;padding-top:3px}
.wunit.is-complete .wunit-say b{opacity:.55;text-decoration:line-through}
.wunit.is-complete .wunit-mark{color:var(--mint-d,#1F7A4C)}
.wunit.is-waiting .wunit-mark{color:var(--butter-d,#8A6410)}
.wunit.is-waiting .wunit-say span{color:var(--butter-d,#8A6410);opacity:.9}
.wunit.is-cancelled .wunit-say b{opacity:.4;text-decoration:line-through}
/* Optional work is real work and should not shout. */
.wunit.is-optional .wunit-say b{font-weight:500}
.wunit-add{margin-top:var(--s2)}

/* ── the same rows, on a phone ──────────────────────────────────────────
   Measured at 430px before this existed: the mark was 22×22 and the add
   button 28 tall, against a floor of 44. That is a thing you miss twice
   standing on a ladder, and it passed a desktop review without comment.

   The glyph stays the size it was; the part you can hit grows around it. */
@media (max-width:760px){
  /* Work first. On a desktop the job card leads, which is right when you are
     looking at the whole thing at once; on a phone the person holding it is
     standing in front of the work and wants to know what they are doing
     before what it is being charged at. The main column is already a flex
     column, so this is an ordering and not a rearrangement — the desktop
     information architecture is untouched. */
  .wunits{gap:2px}
  .wunit{padding:6px var(--s2);gap:var(--s2);align-items:center}
  .wunit-mark{width:44px;height:44px;font-size:19px;flex:none}
  .wunit-say b{font-size:15px;line-height:1.3}
  .wunit-say span{font-size:13px}
  /* The counts move under the title rather than fighting it for width, and
     a long waiting reason wraps instead of squeezing the name to nothing. */
  .wunit{flex-wrap:wrap}
  .wunit-say{flex:1 1 auto;min-width:0}
  .wunit > i{flex:0 0 100%;margin-left:56px;padding-top:2px;font-size:12px;
    white-space:normal}
  .wunit-add{margin-top:var(--s3)}
  .wunit-add .sys-b{min-height:44px;width:100%;justify-content:center;
    font-size:13px;letter-spacing:.06em}
}

/* ── what you mostly do ─────────────────────────────────────────────────
   Four choices, said as what somebody does rather than as a setting. Big
   enough to hit on a phone, because the person most likely to change this
   is the one holding one. */
.ctxpick{display:grid;grid-template-columns:1fr 1fr;gap:var(--s2);padding:0 22px 18px}
.ctxopt{display:flex;flex-direction:column;gap:2px;align-items:flex-start;
  text-align:left;padding:13px 15px;min-height:44px;border:1.5px solid var(--line);
  border-radius:var(--r2);background:var(--white);cursor:pointer;font:inherit}
.ctxopt:hover{border-color:var(--ink)}
.ctxopt b{font-weight:600;font-size:14.5px}
.ctxopt span{font-size:12.5px;opacity:.6;line-height:1.35}
.ctxopt.on{border-color:var(--orange);background:var(--peach)}
.ctxopt.on span{opacity:.75}
@media (max-width:760px){ .ctxpick{grid-template-columns:1fr} }

/* ── a Subject's own screen ──────────────────────────────────────────────
   Two classes, because everything else on it is `sys-*` and `srow` from the
   parts the Job page already uses. A Subject page that needed its own
   layout language would be an assets module wearing a disguise. */
/* A line inside a card. `row()` from shared.js could not do this job: .srow
   is a standalone tappable block for the cream page background — its own
   fill, its own radius, its own left stripe — so inside a white card it read
   as a card within a card. And `.srow .tm` is a SIXTY-FOUR PIXEL COLUMN
   MEANT FOR A TIME, which is why putting a dot in it left the mark stranded
   a thumb's width from the words it belonged to.

   So: a hairline between lines, the same 7px rhythm and the same type sizes
   as `.kv` two hundred lines up, because Details and the lists beside it are
   the same card and should not look like two products. */
.subj-row{display:flex;align-items:baseline;gap:var(--s3);padding:7px 0;
  border-bottom:1px solid var(--line-2)}
.subj-row:last-child{border-bottom:0}
.subj-row .bd{flex:1;min-width:0}
.subj-row .bd b{display:block;font-size:13.5px;font-weight:700;
  letter-spacing:-.012em;overflow-wrap:anywhere}
.subj-row .bd span{display:block;font-size:12px;color:var(--text-2);
  font-weight:600;margin-top:1px}
.subj-row .at{font-size:12px;color:var(--text-2);font-weight:600;flex:none}
.subj-row[data-work]{cursor:pointer}
.subj-row[data-work]:hover .bd b{color:var(--orange-btn)}

.subj-acts{display:flex;flex-wrap:wrap;gap:var(--s2)}
.subj-acts .sys-b{min-height:var(--tap)}
.subj-files{display:flex;flex-wrap:wrap;gap:var(--s2)}

/* On a phone they share one row rather than stacking. Full-width each was
   three stacked bars and a hundred and sixty pixels of buttons before the
   first thing that had happened to the pump — on a 430px screen that is half
   of what you can see at once spent on things you might not do.

   Sharing the row still leaves each of them about 125px wide and the full
   44px tall, which is a target for a cold hand standing outside. On a
   desktop they stay their own size, because a button stretched across a
   column is a button pretending to be a banner. */
@media (max-width:760px){
  .subj-acts{gap:var(--s1)}
  .subj-acts .sys-b{flex:1 1 0;min-width:0;padding:0 8px}
}

/* ── a customer's places ─────────────────────────────────────────────────
   A line, not a card. These sit inside `.sys-card` beside Contact and Notes,
   and the same hairline rhythm as `.kv` keeps the column reading as one
   thing rather than three products stacked. */
.plc{display:flex;align-items:baseline;gap:var(--s3);padding:7px 0;
  border-bottom:1px solid var(--line-2);cursor:pointer}
.plc:last-of-type{border-bottom:0}
.plc .bd{flex:1;min-width:0}
.plc .bd b{display:block;font-size:13.5px;font-weight:700;letter-spacing:-.012em}
.plc .bd span{display:block;font-size:12px;color:var(--text-2);font-weight:600;
  margin-top:1px;overflow-wrap:anywhere}
.plc:hover .bd b{color:var(--orange-btn)}
/* Which one work is offered at first. A word at the weight of a caption,
   because a coloured chip here would compete with the state chips that mean
   something is wrong. */
.plc-def{font-style:normal;font-size:10.5px;font-weight:800;margin-left:8px;
  letter-spacing:.04em;text-transform:uppercase;color:var(--text-2)}
/* What is at it, which is the one thing a place says that nothing else does. */
.plc-at{font-size:12px;color:var(--text-2);font-weight:600;flex:none;
  white-space:nowrap}
.plc-add{padding-top:10px}
.plc-more{display:flex;flex-wrap:wrap;gap:var(--s2);padding-top:var(--s3);
  border-top:1px solid var(--line-2);margin-top:var(--s3)}

@media (max-width:760px){
  /* On a phone the count moves under the name rather than fighting a long
     address for the same row. */
  .plc{flex-wrap:wrap}
  .plc-at{width:100%;padding-top:2px}
  .plc-more .sys-b{flex:1 1 100%}
}

/* ══ THE VISUAL SYSTEM PASS · 22 September ═══════════════════════════════
   Three shared changes, after looking at Home, Subject, Job and Customer
   side by side and finding the symptoms had common causes.

   Home is the reference and is not touched: `.home-*`, `.hcard`, `.need`,
   `.b1/.b2` and its phone reordering are left exactly as they are.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1 · a record has a width ────────────────────────────────────────────
   The single cause of most of it. No content page had a max-width, so every
   object page stretched to the glass: a label at the far left of a card and
   its value a hand's width away at the other end, cards floating rather
   than composed, and the bottom half of the Subject screen empty.

   1180px is where operational density still reads as a composition. Wider
   and the key/value rows come apart again; much narrower and a job sheet
   stops being dense, which is the opposite mistake. A maximum, not a width:
   below it the page still uses everything it has.

   Only `objectPage()` sets it. A diary, a report or a stock list wants the
   whole screen, and Home composes its own full-bleed hero. */
/* `width:100%` as well as the maximum. A flex child with `margin:auto` and
   no width shrinks to its content, so the page collapsed to the width of its
   widest card and sat marooned in the middle of the screen — narrower than
   the stretch it was meant to fix. */
.sys-measure{ width:100%; max-width:1600px; margin-inline:auto }

/* ── 2 · one hairline row, four names ────────────────────────────────────
   `.kv`, `.fact`, `.subj-row` and `.plc` were four sets of hand-typed
   padding and type sizes doing one job: a line inside a grouped surface.
   Four rhythms on one screen is what "generic admin" looks like up close,
   so the shared half lives here once and each keeps only what is its own.

   Not `.srow`, deliberately — that is a standalone tappable block for the
   cream page background and its lead slot is a 64px time column. */
.kv, .fact, .subj-row, .plc{
  padding-block:7px;
  border-bottom:1px solid var(--line-2);
}
.kv:last-child, .fact:last-child, .subj-row:last-child, .plc:last-of-type{
  border-bottom:0;
}
.fact > span, .kv > span, .subj-row .bd span, .plc .bd span{
  font-size:12px; font-weight:600; color:var(--text-2);
}
.fact > b, .kv > b, .subj-row .bd b, .plc .bd b{
  font-size:13.5px; font-weight:700; letter-spacing:-.012em;
}

/* ── 3 · history is not current work ────────────────────────────────────
   On the Subject these were the same card with the same rows and a
   different heading, so "what is happening now" and "what has happened"
   read as one undifferentiated list. They are different kinds of fact: one
   is a thing you act on, the other a sequence you read.

   So history becomes a sequence — a rule down the left, a mark per entry,
   the date leading — and current work stays a list of rows you open. The
   distinction is structural, not decorative: no extra colour, no icons,
   one hairline and a dot. */
.tl{ position:relative; padding-left:18px }
.tl:before{ content:''; position:absolute; left:3px; top:10px; bottom:10px;
  width:1px; background:var(--line) }
.tl-row{ position:relative; display:flex; align-items:baseline;
  gap:var(--s3); padding-block:8px }
.tl-row:before{ content:''; position:absolute; left:-18px; top:13px;
  width:7px; height:7px; border-radius:50%; background:var(--line);
  box-shadow:0 0 0 3px var(--white) }
.tl-row.at:before{ background:var(--orange) }
.tl-when{ font-size:11.5px; font-weight:700; color:var(--text-2);
  flex:none; width:52px; font-variant-numeric:tabular-nums }
.tl-what{ flex:1; min-width:0 }
.tl-what b{ display:block; font-size:13.5px; font-weight:700;
  letter-spacing:-.012em; overflow-wrap:anywhere }
.tl-what span{ display:block; font-size:12px; color:var(--text-2);
  font-weight:600; margin-top:1px }
.tl-row[data-work]{ cursor:pointer }
.tl-row[data-work]:hover .tl-what b{ color:var(--orange-btn) }

/* On a phone the date goes above the entry rather than squeezing the words
   it belongs to into a column two characters wide. */
@media (max-width:760px){
  .tl-row{ flex-wrap:wrap }
  .tl-when{ width:100%; order:-1; padding-bottom:1px }
}

/* ── 4 · one action cluster, not floating pills ─────────────────────────
   The Subject had a primary in the header and three more pills on a row
   below, reading as four unrelated offers. One cluster now: the quiet ones
   together, the primary where every object page keeps it, so there is one
   place the eye looks for "what can I do". */
.sys-acts{ display:flex; flex-wrap:wrap; gap:var(--s2); align-items:center }
.sys-acts .sys-b{ min-height:var(--tap) }
@media (max-width:760px){
  .sys-acts .sys-b{ flex:1 1 0; min-width:0; padding:0 8px }
}

/* ═══════════════════════════════════════════════════════════════════════
   BUILD YOUR NOTI — Settings → Modules (24 Sep; redrawn 25 Sep)
   The owner (25 Sep): it did not use the width and could look better. On a
   wide screen the catalogue takes the room and "Your Noti" — what you pay
   and for what — stays in view beside it, the way a configurator keeps the
   total next to the choices. Packages and modules are cards that say what
   they include; detail is still in a sheet. One column on a phone, with the
   total first.
   ═══════════════════════════════════════════════════════════════════════ */
.nb-head{ display:flex; align-items:flex-end; justify-content:space-between; gap:16px; flex-wrap:wrap }
.nb-eyebrow{ font-size:10.5px; font-weight:800; letter-spacing:.12em; text-transform:uppercase;
  color:var(--orange-btn); margin-bottom:2px }
.nb-per{ font-size:12.5px; font-weight:600; color:var(--text-2); margin-left:1px }

.nb-grid{ display:grid; grid-template-columns:minmax(0,1fr) 300px; gap:var(--s4); align-items:start; margin-top:var(--s3) }
.nb-main{ display:flex; flex-direction:column; gap:var(--s4); min-width:0 }
.nb-side{ position:sticky; top:var(--s4) }

/* ── Base: the foundation, full width ────────────────────────────────── */
.nb-base{ background:var(--white); border:1px solid var(--line); border-radius:var(--r);
  padding:16px 20px; position:relative; overflow:hidden }
.nb-base::before{ content:""; position:absolute; inset:0 auto 0 0; width:5px; background:var(--orange) }
.nb-base-top{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px }
.nb-base-name{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; min-width:0 }
.nb-base-name h2{ font-size:19px; font-weight:800; letter-spacing:-.02em }
.nb-base .nb-price{ font-size:20px; font-weight:800; letter-spacing:-.02em; white-space:nowrap }
.nb-blurb{ margin-top:4px; font-size:14px; line-height:20px; color:var(--mid); max-width:62ch }
.nb-loop{ list-style:none; display:flex; flex-wrap:wrap; gap:8px 20px; margin-top:10px; padding:0 }
.nb-loop li{ font-size:12px; font-weight:700; color:var(--ink); display:flex; align-items:center;
  background:var(--cream); border-radius:99px; padding:3px 10px }
.nb-loop li{ position:relative }
.nb-loop li:not(:last-child)::after{ content:"\2192"; position:absolute; right:-15px;
  color:var(--orange); font-weight:800 }
.nb-inc{ margin-top:10px; border-top:1px solid var(--line-2); padding-top:2px }
.nb-inc summary{ cursor:pointer; font-size:13px; font-weight:700; color:var(--ink);
  list-style:none; min-height:var(--tap); display:flex; align-items:center }
.nb-inc summary::-webkit-details-marker{ display:none }
.nb-inc summary::after{ content:"+"; margin-left:8px; color:var(--orange-btn); font-weight:800 }
.nb-inc[open] summary::after{ content:"\2212" }
.nb-ticks{ list-style:none; padding:0; margin:4px 0 0; display:grid;
  grid-template-columns:repeat(auto-fill, minmax(230px, 1fr)); gap:8px 20px }
.nb-ticks li, .nb-tick{ display:flex; gap:8px; align-items:flex-start; font-size:13.5px; line-height:19px; color:var(--mid) }
.nb-ticks li::before, .nb-tick::before{ content:""; flex:none; width:16px; height:16px; margin-top:1px; border-radius:50%;
  background:var(--mint) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2317633C' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E") center/10px no-repeat }
.nb-base-act{ display:flex; align-items:center; gap:10px; margin-top:14px; flex-wrap:wrap }
.nb-note{ font-size:12.5px; color:var(--text-2) }

.nb-state{ font-size:11px; font-weight:800; letter-spacing:.02em; padding:3px 9px; border-radius:99px;
  background:var(--cream); color:var(--text-2); white-space:nowrap }
.nb-state.on{ background:var(--orange-l); color:var(--orange-btn) }
.nb-state.save{ background:#E6F2EA; color:#2D6A45 }

/* ── sections ───────────────────────────────────────────────────────── */
.nb-sect{ display:flex; flex-direction:column; gap:8px }
.nb-sect-head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; flex-wrap:wrap }
.nb-h2{ font-size:15.5px; font-weight:800; letter-spacing:-.015em; color:var(--ink) }
.nb-sect-note{ font-size:13px; color:var(--text-2) }

/* ── cards: a package or a module ────────────────────────────────────── */
.nb-cards{ list-style:none; padding:0; margin:0; display:grid; gap:10px;
  grid-template-columns:repeat(auto-fit, minmax(250px, 1fr)) }
.nb-card{ display:flex }
.nb-card-hit{ width:100%; display:flex; flex-direction:column; gap:6px; text-align:left;
  padding:14px 16px; background:var(--white); border:1px solid var(--line); border-radius:var(--r2);
  font:inherit; color:var(--ink); cursor:pointer; transition:border-color .12s, box-shadow .12s }
.nb-card-hit:hover{ border-color:var(--ink); box-shadow:0 6px 18px rgba(26,22,19,.06) }
.nb-card.active .nb-card-hit{ border-color:var(--orange); box-shadow:inset 0 0 0 1px var(--orange) }
.nb-card-top{ display:flex; align-items:flex-start; justify-content:space-between; gap:10px }
.nb-row-name{ font-size:15px; font-weight:800; letter-spacing:-.015em; overflow-wrap:anywhere }
.nb-row-blurb{ font-size:13px; line-height:18px; color:var(--mid) }
.nb-parts{ display:flex; flex-wrap:wrap; gap:6px }
.nb-part{ font-size:11.5px; font-weight:700; padding:2px 8px; border-radius:99px; background:var(--cream); color:var(--ink) }
.nb-card .nb-tick{ font-size:12.5px; line-height:17px }
.nb-card-ticks{ display:flex; flex-direction:column; gap:3px }
.nb-card-foot{ margin-top:auto; padding-top:8px; display:flex; align-items:center; justify-content:space-between; gap:10px;
  border-top:1px solid var(--line-2) }
.nb-pay{ display:flex; flex-direction:column; gap:1px }
.nb-was{ font-size:12px; color:var(--text-2); font-weight:600 }
.nb-card .nb-price{ font-size:17px; font-weight:800; letter-spacing:-.02em; white-space:nowrap }
.nb-row-go{ display:inline-flex; align-items:center; justify-content:center; min-height:var(--tap); padding:0 16px;
  border-radius:99px; background:var(--ink); color:#fff; font-size:13px; font-weight:700; white-space:nowrap }
.nb-card.active .nb-row-go{ background:var(--cream); color:var(--ink) }
/* With a mouse the button can be compact; a finger keeps 44px. */
@media (pointer:fine){ .nb-row-go{ min-height:34px; padding:0 14px } }

/* ── coming later ───────────────────────────────────────────────────── */
.nb-sect--later .nb-h2{ color:var(--text-2) }
.nb-later{ list-style:none; padding:0; margin:0; display:grid; gap:10px;
  grid-template-columns:repeat(auto-fit, minmax(220px, 1fr)) }
.nb-later-row{ display:flex; flex-direction:column; gap:2px; padding:10px 14px;
  border:1.5px dashed var(--line); border-radius:var(--r2) }
.nb-later-row .nb-row-name{ font-size:14.5px; color:var(--mid) }
.nb-later-row .nb-row-blurb{ font-size:12.5px; color:var(--text-2) }

/* ── Your Noti: the total, kept in view ──────────────────────────────── */
.nb-sum{ background:var(--ink); color:#fff; border-radius:var(--r); padding:16px 18px }
.nb-sum-label{ font-size:10.5px; font-weight:800; letter-spacing:.12em; text-transform:uppercase; color:#A69C92 }
.nb-sum-total{ font-size:30px; font-weight:800; letter-spacing:-.03em; margin-top:4px }
.nb-sum-total .nb-per{ color:#A69C92; font-size:13px }
.nb-sum-lines{ list-style:none; padding:0; margin:14px 0 0; display:flex; flex-direction:column; gap:8px;
  border-top:1px solid rgba(255,255,255,.12); padding-top:12px }
.nb-sum-lines li{ display:flex; justify-content:space-between; gap:12px; font-size:13.5px; color:#E9E2D8 }
.nb-sum-lines li span:last-child{ font-weight:700; white-space:nowrap }
.nb-sum-note{ margin-top:14px; font-size:12px; line-height:17px; color:#A69C92 }

.nb-sheet h3{ font-size:10.5px; font-weight:800; letter-spacing:.12em; text-transform:uppercase;
  color:var(--text-2); margin:14px 0 6px }
.nb-sheet ul{ margin:2px 0 4px 18px; display:flex; flex-direction:column; gap:5px;
  font-size:13.5px; color:var(--mid) }
.nb-sheet p{ font-size:13.5px; line-height:19px; color:var(--mid) }
.nb-sheet p + p{ margin-top:8px }
.nb-sheet-price{ font-size:22px; font-weight:800; letter-spacing:-.02em }

@media (max-width:1100px){
  .nb-grid{ grid-template-columns:1fr }
  .nb-side{ position:static; order:-1 }
  .nb-sum{ display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:4px 16px; padding:16px 18px }
  .nb-sum-total{ font-size:26px; margin-top:0 }
  .nb-sum-lines, .nb-sum-note{ flex-basis:100%; margin-top:8px }
  /* One line is the Base card below saying the same thing. */
  .nb-sum.single .nb-sum-lines{ display:none }
}
@media (max-width:560px){
  .nb-base{ padding:18px 16px }
  .nb-loop{ gap:8px 15px }
  .nb-loop li{ padding:4px 8px; font-size:12px }
  .nb-loop li:not(:last-child)::after{ right:-12px }
  .nb-base-name h2{ font-size:19px }
  .nb-base .nb-price{ font-size:20px }
  .nb-cards, .nb-later{ grid-template-columns:1fr }
  /* The sentence says what it is for; View has the full list. */
  .nb-card-ticks{ display:none }
  .nb-card-hit{ padding:16px }
}

/* ═══════════════════════════════════════════════════════════════════════
   THE CALL CARD — Noti Phone in the browser (voice v1, 25 Sep 2026)
   On <body>, outside the page, so changing screens never drops a call.
   Desk: a card at the bottom right. Phone (≤860px): a sheet over the tab
   bar, buttons big enough to hit one-handed. nc- only.
   ═══════════════════════════════════════════════════════════════════════ */
.nc{ position:fixed; right:20px; bottom:20px; z-index:70; width:340px; max-width:calc(100vw - 32px);
  background:var(--ink); color:#fff; border-radius:var(--r); padding:16px 16px 14px;
  box-shadow:0 18px 50px rgba(26,22,19,.35); display:flex; flex-direction:column; gap:10px;
  font-family:inherit }
.nc[hidden]{ display:none }
.nc-top{ display:flex; align-items:center; gap:8px; font-size:11.5px; font-weight:800;
  letter-spacing:.1em; text-transform:uppercase; color:#A69C92 }
.nc-dot{ width:8px; height:8px; border-radius:50%; background:var(--mint-d2) }
.nc-ringing .nc-dot{ background:var(--attn); animation:nc-pulse 1.1s ease-in-out infinite }
.nc-time{ margin-left:auto; font-variant-numeric:tabular-nums; color:#fff; letter-spacing:0; font-size:13px }
@keyframes nc-pulse{ 0%,100%{ box-shadow:0 0 0 0 rgba(176,62,20,.6) } 50%{ box-shadow:0 0 0 7px rgba(176,62,20,0) } }
.nc-who{ display:flex; flex-direction:column; gap:2px; min-width:0 }
.nc-who b{ font-size:20px; font-weight:800; letter-spacing:-.02em; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.nc-who span{ font-size:13px; color:#CFC6BB; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.nc-links{ display:flex; flex-wrap:wrap; gap:6px }
.nc-link{ min-height:36px; padding:0 12px; border-radius:99px; border:1px solid rgba(255,255,255,.18);
  background:none; color:#fff; font:inherit; font-size:13px; font-weight:700; cursor:pointer;
  max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.nc-acts{ display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-top:2px }
.nc-b{ min-height:52px; border:0; border-radius:16px; display:flex; align-items:center; justify-content:center; gap:8px;
  background:rgba(255,255,255,.1); color:#fff; font:inherit; font-size:14.5px; font-weight:800; cursor:pointer }
.nc-b svg{ width:20px; height:20px; stroke:currentColor; fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round }
.nc-b.on{ background:#fff; color:var(--ink) }
.nc-yes{ background:var(--mint-d2) }
.nc-no{ background:#C2410C }
@media (max-width:699px){
  .nc{ left:8px; right:8px; bottom:calc(8px + env(safe-area-inset-bottom)); width:auto; max-width:none;
    border-radius:22px; padding:18px 16px 16px }
  .nc-b{ min-height:58px; font-size:15.5px }
  .nc-link{ min-height:var(--tap) }
}
@media (prefers-reduced-motion:reduce){ .nc-ringing .nc-dot{ animation:none } }

/* The Customer Inbox's calls switch (Noti Phone). */
.ib-taking{ min-height:36px; padding:0 14px; border-radius:99px; border:1.5px solid var(--line);
  background:var(--white); color:var(--text-2); font:inherit; font-size:13px; font-weight:700; cursor:pointer;
  margin-right:8px }
.ib-taking.on{ border-color:var(--mint-d2); color:var(--mint-d2) }
.ib-taking.on::before{ content:""; display:inline-block; width:8px; height:8px; border-radius:50%;
  background:var(--mint-d2); margin-right:7px; vertical-align:1px }
@media (pointer:coarse){ .ib-taking{ min-height:var(--tap) } }

/* A call in the Customer Inbox thread (Noti Phone): on the side of whoever
   rang, like a message (WhatsApp does the same), so a run of calls reads as
   the conversation it was rather than a stack of cards down the middle. The
   missed ones warm. */
.ib-call-row{ align-self:flex-start; display:flex; align-items:center; gap:10px; max-width:min(84%,420px);
  padding:6px 12px 6px 8px; border-radius:18px; border-bottom-left-radius:6px;
  background:var(--white); box-shadow:0 0 0 1px var(--line-2) }
.ib-call-row.out{ align-self:flex-end; border-bottom-left-radius:18px; border-bottom-right-radius:6px }
.ib-call-ic{ flex:none; width:30px; height:30px; border-radius:50%; display:grid; place-items:center;
  background:var(--mint); color:var(--mint-d2) }
.ib-call-ic svg{ width:16px; height:16px; stroke:currentColor; fill:none; stroke-width:2 }
.ib-call-row.missed .ib-call-ic{ background:var(--attn-l); color:var(--attn) }
.ib-call-txt{ display:flex; flex-direction:column; min-width:0 }
.ib-call-txt b{ font-size:13.5px }
.ib-call-txt span{ font-size:12px; color:var(--text-2) }
.ib-call-txt em{ font-style:normal; color:var(--attn); font-weight:800 }
.ib-vm{ margin-left:auto; min-height:var(--tap); padding:0 14px; border:0; border-radius:99px;
  background:var(--ink); color:#fff; font:inherit; font-size:13px; font-weight:700; display:flex; align-items:center; gap:6px; cursor:pointer }
.ib-vm svg{ width:14px; height:14px; stroke:currentColor; fill:none; stroke-width:2.4 }
.ib-audio{ align-self:flex-start; width:min(92%,420px) }
/* On a phone the Play button keeps its 44px but loses its word, so the call's
   own words are not squeezed into a column one word wide. */
@media (max-width:560px){
  .ib-call-row{ max-width:92% }
  .ib-vm{ padding:0; width:var(--tap); justify-content:center }
  .ib-vm span{ display:none } }

/* Settings → Calls (Noti Phone). Rows that stack on a phone; switches that
   are 44px under a finger. cl- only. */
.cl-list{ display:flex; flex-direction:column; padding:0 22px }
.cl-form, .cl-hours, .cl-nums{ padding:0 22px 20px }
.cl-row{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:12px 0;
  border-bottom:1px solid var(--line-2); flex-wrap:wrap }
.cl-row:last-child{ border-bottom:0 }
.cl-who{ display:flex; flex-direction:column; min-width:0; flex:1 1 180px }
.cl-who b{ font-size:14.5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.cl-who span{ font-size:12.5px; color:var(--text-2) }
.cl-on{ font-style:normal; color:var(--mint-d2); font-weight:700; text-transform:none }
.cl-tgs{ display:flex; gap:8px; flex-wrap:wrap }
.cl-tg{ min-height:38px; padding:0 14px; border-radius:99px; border:1.5px solid var(--line); background:var(--white);
  color:var(--text-2); font:inherit; font-size:13px; font-weight:700; cursor:pointer; white-space:nowrap }
.cl-tg.on{ border-color:var(--mint-d2); background:var(--mint); color:var(--mint-d2) }
.cl-tg.add{ border-style:dashed }
.cl-tg:disabled{ cursor:default; opacity:.7 }
.cl-form{ display:flex; flex-direction:column; gap:12px; max-width:520px }
.cl-field{ display:flex; flex-direction:column; gap:4px }
.cl-field span{ font-size:12.5px; font-weight:700; color:var(--text-2) }
.cl-field select{ min-height:var(--tap); border-radius:12px; border:1.5px solid var(--line); background:var(--cream-2);
  padding:0 12px; font:inherit; font-size:15px }
.cl-form .sys-b{ align-self:flex-start }
.cl-field textarea{ border-radius:12px; border:1.5px solid var(--line); background:var(--cream-2);
  padding:10px 12px; font:inherit; font-size:15px; line-height:1.4; resize:vertical; min-height:64px }
.cl-hours{ display:flex; flex-direction:column; gap:6px }
.cl-day{ display:grid; grid-template-columns:90px 1fr auto 1fr; align-items:center; gap:8px; max-width:440px }
.cl-open{ display:flex; align-items:center; gap:8px; min-height:var(--tap); font-weight:700; font-size:14px }
.cl-open input{ width:18px; height:18px }
.cl-day input[type=time]{ min-height:40px; border-radius:10px; border:1.5px solid var(--line); background:var(--cream-2);
  padding:0 8px; font:inherit; font-size:15px; min-width:0 }
.cl-to{ font-size:12.5px; color:var(--text-2) }
.cl-acts{ display:flex; gap:8px; flex-wrap:wrap; margin-top:4px }
.cl-num{ display:flex; flex-direction:column; padding:6px 0 }
.cl-num span{ font-size:12.5px; color:var(--text-2) }
@media (pointer:coarse){ .cl-tg{ min-height:var(--tap) } .cl-day input[type=time]{ min-height:var(--tap) } }
@media (max-width:560px){
  .cl-day{ grid-template-columns:1fr auto 1fr; grid-template-areas:"open open open" "from to till";
    row-gap:2px; padding-bottom:6px; border-bottom:1px solid var(--line-2) }
  .cl-open{ grid-area:open } .cl-day [data-cl-from]{ grid-area:from } .cl-to{ grid-area:to } .cl-day [data-cl-till]{ grid-area:till } .cl-list{ padding:0 16px } .cl-form, .cl-hours, .cl-nums{ padding:0 16px 16px } }

.cl-result{ font-size:13.5px; line-height:1.45; overflow-wrap:anywhere }
.cl-result.ok{ color:var(--mint-d2); font-weight:700 }
.cl-result.bad{ color:var(--attn); font-weight:700 }

/* The customer's Messages tab: the Customer Inbox thread, in the record. */
/* A conversation is read down a column, not across a 1900px screen: past
   about 860px the bubbles drift to opposite edges and the eye loses them. */
.cu-talk{ display:flex; flex-direction:column; gap:10px; background:var(--white); border-radius:var(--r); padding:14px;
  max-width:860px }
.cu-talk-acts{ display:flex; gap:8px; flex-wrap:wrap }
.cu-talk-acts a.sys-b{ text-decoration:none; display:inline-flex; align-items:center; gap:8px }
.cu-call svg{ width:17px; height:17px; stroke:currentColor; fill:none; stroke-width:2 }
.cu-thread{ max-height:min(60vh, 560px); min-height:160px; border-radius:var(--r2); background:var(--cream-2) }
.cu-compose{ border-top:0; padding:0; background:none }

.cl-code{ min-height:var(--tap); border-radius:12px; border:1.5px solid var(--line); background:var(--cream-2);
  padding:0 14px; font:inherit; font-size:16px; max-width:240px }

/* Your plan: the owner's actions, a row of real buttons under the facts. */
.pl-acts{ display:flex; flex-wrap:wrap; gap:8px; padding:14px 12px 2px }
.pl-say{ margin:8px 12px 0 }
.pl-card-el{ min-height:220px; margin-top:6px }

/* Money → a payment row. On a desk: time column, what, amount, Refund. On a
   phone the 64px time column and the Refund button left a sale's name one
   word per line (TODO, 24 Sep): the time moves into the second line and
   Refund drops under the amount, so the name gets the width. */
.pay-row .pay-when{ display:none; font-style:normal }
@media (max-width:560px){
  .pay-row{ flex-wrap:wrap; row-gap:8px }
  .pay-row .tm{ display:none }
  .pay-row .pay-when{ display:inline }
  .pay-row .bd{ flex:1 1 55%; min-width:0 }
  .pay-row .rowbtn{ order:3; margin-left:auto; min-height:var(--tap) } }

/* ── page primitives (LAYOUT.md) ──────────────────────────────────────
   .sys-cols  cards that read on their own flow two across from a desktop
              (1440) — Money's overview, Settings' cards — instead of one
              1,600px-wide column with a label at one edge and its number at
              the other. .span-all keeps a card across both.
   .sys-grid  rows of people or things that are the same kind (Team) sit two
              across from a laptop and three on a large screen. */
.sys-cols{ display:flex; flex-direction:column; gap:var(--gap) }
@media (min-width:1440px){
  .sys-cols{ display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); align-items:start }
  .sys-cols > .span-all{ grid-column:1 / -1 }
}
@media (min-width:1100px){
  .sched.sys-grid{ display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:8px }
}
@media (min-width:1920px){
  .sched.sys-grid{ grid-template-columns:repeat(3, minmax(0, 1fr)) }
}

/* A customer's read: one line of what Noti noticed, dot beside it. */
.cu-read{ display:flex; align-items:flex-start; gap:10px }
.cu-read .dot{ margin-top:6px; flex:none }
.cu-read .m b{ display:block; font-size:13px; font-weight:800 }
.cu-read .m p{ margin:2px 0 0; font-size:13.5px; color:var(--text-2) }

/* The Inbox fills the screen it is on (it capped at 760px and left a band of
   nothing under a tall monitor), and a large screen gets a wider list. */
@media (min-width:1920px){ .ib{ grid-template-columns:400px 1fr } }

/* ── Customers, desktop up: the list beside the open record ─────────────
   The Customer Inbox's shape: a quiet list on the left that stays put, the
   record on the right. Sticky and scrolling on its own, so a long list never
   drags the record down with it. */
.cu-split{ display:grid; grid-template-columns:340px minmax(0, 1fr); gap:var(--gap); align-items:start }
@media (min-width:1920px){ .cu-split{ grid-template-columns:380px minmax(0, 1fr) } }
.cu-main{ min-width:0 }
.cu-side{ position:sticky; top:14px; max-height:calc(100dvh - 28px); display:flex; flex-direction:column;
  background:var(--white); border-radius:var(--r); overflow:hidden; box-shadow:0 0 0 1px var(--line-2) }
.cu-side-head{ display:flex; justify-content:space-between; align-items:baseline; padding:16px 18px 10px }
.cu-side-head b{ font-size:15px; font-weight:800; letter-spacing:-.015em }
.cu-side-head span{ font-size:12.5px; font-weight:700; color:var(--text-2) }
.cu-side-q{ margin:0 12px 10px; min-height:40px; border-radius:99px; border:1.5px solid var(--line);
  background:var(--cream-2); padding:0 16px; font:inherit; font-size:14px; color:var(--ink); outline:none }
.cu-side-q:focus{ border-color:var(--ink); background:var(--white) }
.cu-side-list{ overflow-y:auto; overscroll-behavior:contain; padding:0 8px 10px; display:flex; flex-direction:column; gap:2px }
.cu-side-row{ display:flex; align-items:center; gap:11px; width:100%; min-height:52px; padding:8px 10px;
  border:0; border-radius:13px; background:none; text-align:left; font:inherit; color:inherit; cursor:pointer }
.cu-side-row:hover{ background:var(--cream-2) }
.cu-side-row.on{ background:var(--cream); box-shadow:inset 3px 0 0 var(--orange) }
.cu-side-row .av{ width:32px; height:32px; font-size:11.5px; flex:none }
.cu-side-row .m{ flex:1; min-width:0 }
.cu-side-row .m b{ display:block; font-size:13.5px; font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.cu-side-row .m span{ display:block; font-size:12px; color:var(--text-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.cu-side-row em{ flex:none; font-style:normal; font-size:13px; font-weight:800; font-variant-numeric:tabular-nums }
.cu-side-row em.bad{ color:var(--attn) }
.cu-side-none{ padding:14px 12px; font-size:13px; color:var(--text-2) }

/* ── Products as a table, laptop up ───────────────────────────────────── */
.pr-head, .pr-row .pr-c, .srow.pr-row .pr-wide, .srow.pr-row .bd .pr-wide{ display:none }
@media (min-width:1100px){
  .pr-list{ gap:4px }
  .pr-head, .srow.pr-row{ display:grid; align-items:center; column-gap:16px;
    grid-template-columns:minmax(0, 1fr) 104px 96px 72px 150px 116px }
  .pr-head{ padding:2px 15px 6px 16px; font-size:11px; font-weight:800; letter-spacing:.08em;
    text-transform:uppercase; color:var(--text-2) }
  .pr-head span:nth-child(n+2){ text-align:right }
  .pr-head span:nth-child(5){ text-align:left }
  .pr-row .pr-c{ display:block; font-size:13.5px; font-weight:600; white-space:nowrap }
  .pr-row .pr-c.num{ text-align:right; font-variant-numeric:tabular-nums }
  .srow.pr-row .pr-wide, .srow.pr-row .bd .pr-wide{ display:block }
  .srow.pr-row .pr-narrow, .srow.pr-row .bd .pr-narrow{ display:none }
  .pr-row .pill{ justify-self:start }
  .pr-row .amt{ text-align:right }
  .pr-row.sub{ margin-left:0 }
  .pr-row.sub .bd{ padding-left:22px }
}
@media (min-width:1920px){
  .pr-head, .srow.pr-row{ grid-template-columns:minmax(0, 1fr) 120px 110px 84px 170px 130px }
}

/* ── a customer's Now ──────────────────────────────────────────────────── */
.cu-now{ display:flex; flex-direction:column; gap:2px; margin:0 -8px }
.cu-now-row{ display:flex; align-items:center; gap:12px; width:100%; min-height:var(--tap);
  padding:10px 8px; border:0; border-radius:12px; background:none; text-align:left;
  font:inherit; color:inherit; cursor:pointer }
.cu-now-row:hover{ background:var(--cream-2) }
.cu-now-row .m{ flex:1; min-width:0 }
.cu-now-row .m b{ display:block; font-size:14.5px; font-weight:700; line-height:1.3 }
.cu-now-row .m span{ display:block; font-size:12.5px; color:var(--text-2); margin-top:1px }
.cu-now-row.warn .m span{ color:var(--attn); font-weight:700 }
.cu-now-row em{ font-style:normal; font-weight:800; font-variant-numeric:tabular-nums; font-size:14px }
.cu-now-row svg{ width:16px; height:16px; flex:none; color:var(--faint); stroke:currentColor; fill:none; stroke-width:2 }
.cu-now-more{ margin-top:6px; min-height:36px; padding:0 8px; border:0; background:none;
  color:var(--orange-btn); font:inherit; font-size:13px; font-weight:700; cursor:pointer }

/* Do it again: one more visit, or a regular. Two big answers, thumb-sized. */
.again-pick{ display:grid; gap:10px; margin-top:4px }
.again-pick .again-b{ min-height:48px; width:100%; justify-content:center }

/* An order's figures on a phone: five numbers somebody reads at a glance, two
   across and compact - four full-width cards pushed the lines and the
   deliveries off the first screen (walk, 26 Sep). */
@media (max-width:699px){
  .stats.ord-figs{ grid-template-columns:repeat(2, minmax(0, 1fr)); gap:8px }
  .stats.ord-figs .stat{ padding:12px 14px }
  .stats.ord-figs .stat .v{ font-size:22px; margin-top:6px }
  .stats.ord-figs .stat .ic{ display:none }
}

/* Team -> Customise access: grouped switches, with why a fixed one is fixed. */
.access{display:flex;flex-direction:column;gap:14px}
.access-area{display:flex;flex-direction:column;gap:2px}
.access-area > b{font-size:12.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--text-2);margin-bottom:4px}
.access-row{display:flex;gap:10px;align-items:flex-start;padding:9px 2px;min-height:44px;border-bottom:1px solid var(--line);cursor:pointer}
.access-row input{width:20px;height:20px;margin-top:1px;flex:none;accent-color:var(--orange-btn)}
.access-row span{display:flex;flex-direction:column;font-size:14.5px;line-height:1.35}
.access-row i{font-style:normal;font-size:12px;color:var(--text-2)}
.access-row.fixed{opacity:.6;cursor:default}

/* Where-and-reach now leads the main column (so the rail starts beside it);
   on one column it must still come before The job. */
.jobgrid .jobcol--main > .jobbrief{order:-1}
/* The rail never scrolls inside itself: a card taller than the window cut
   "Request payment" in half at its edge and hid Next inside it (live walk,
   29 Sep). Sticky with no max-height still shows its foot as the page ends. */

/* ── New Job, asked in the order people think (owner, 29 Sep) ───────────
   One sheet of sections, each only when this business has a use for it.
   Choices are chips big enough to hit standing up (44px); the chosen one is
   outlined in ink and tinted, so it reads as chosen without colour alone. */
.nj{display:flex;flex-direction:column}
.nj-sec{padding:var(--s4) 0;border-top:1px solid var(--line)}
.nj-sec:first-child,.nj-restored + .nj-sec{border-top:0;padding-top:0}
.nj-sec[hidden]{display:none}
.nj-sec h3{margin:0 0 var(--s2);font-size:14px;font-weight:800;color:var(--ink)}
.nj select,.nj input[type=text],.nj input[type=tel],.nj input[type=date],.nj input[type=time],.nj textarea{
  width:100%;min-height:44px;font:inherit;font-size:15px;color:var(--ink);background:var(--white);
  border:1px solid #D3C8B9;border-radius:var(--r3);padding:10px 12px;box-sizing:border-box}
.nj textarea{min-height:84px;resize:vertical;line-height:1.45}
.nj ::placeholder{color:#8A7F74}
.nj-new{display:flex;flex-direction:column;gap:var(--s2);margin-top:var(--s2)}
.nj-new[hidden]{display:none}
.nj-chips{display:flex;flex-wrap:wrap;gap:var(--s2)}
.nj-chip{display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:1px;
  min-height:44px;padding:8px 14px;border:1px solid #D3C8B9;border-radius:var(--r3);background:var(--white);
  color:var(--ink);font:inherit;text-align:left;cursor:pointer;max-width:100%}
.nj-chip b{font-size:14.5px;font-weight:700;overflow-wrap:anywhere}
.nj-chip span{font-size:12.5px;font-weight:600;color:#4A423B}
.nj-chip.on{border-color:var(--ink);box-shadow:inset 0 0 0 1px var(--ink);background:var(--orange-l)}
.nj-two .nj-chip,.nj-three .nj-chip{flex:1 1 0;min-width:0}
.nj-f{display:flex;flex-direction:column;gap:5px;margin-top:var(--s3)}
.nj-f[hidden]{display:none}
.nj-chips + .nj-f{margin-top:var(--s3)}
.nj-sec > .nj-f:first-of-type{margin-top:0}
.nj-chips ~ .nj-f:first-of-type{margin-top:var(--s3)}
.nj-f > span{font-size:13px;font-weight:700;color:#4A423B}
.nj-f > span i{font-style:normal;font-weight:500;color:var(--text-2);margin-left:4px}
.nj-when{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) minmax(0,1fr);gap:var(--s2)}
.nj-when .nj-f{margin-top:0}
.nj-when:has(.nj-f:only-child){grid-template-columns:1fr}
.nj-when + .nj-chips{margin-top:var(--s3)}
@media (max-width:699px){
  .nj-when{grid-template-columns:1fr 1fr}
  .nj-when .nj-f:first-child{grid-column:1 / -1}
}
.nj-called{margin:var(--s3) 0 0;font-size:14px;color:#4A423B;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.nj-called b{color:var(--ink)}
.nj-called[hidden]{display:none}
.nj-more{margin-top:var(--s3);align-self:flex-start}
.nj-hint{margin:var(--s2) 0 0;font-size:13px;color:#4A423B}
.nj-hint[hidden]{display:none}
.nj-restored{margin:0 0 var(--s3);padding:10px 12px;border-radius:var(--r3);background:var(--cream-2);
  border:1px solid var(--line);font-size:13.5px;color:#4A423B;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.nj-forms{display:flex;flex-direction:column}
.nj-form{display:flex;align-items:center;gap:10px;min-height:44px;padding:4px 0;border-bottom:1px solid var(--line-2);
  font-size:14.5px;color:var(--ink);cursor:pointer}
.nj-form:last-child{border-bottom:0}
.nj-form input{width:20px;height:20px;flex:none;accent-color:var(--ink)}
.nj-form span{flex:1;min-width:0;overflow-wrap:anywhere}
.nj-form em{font-style:normal;font-size:12px;font-weight:700;color:#4A423B;flex:none}
.nj-form.auto{cursor:default}
/* The job's purpose, changed where it is read (owner, 29 Sep). */
.jscope-wrap{display:flex;align-items:flex-start;gap:var(--s3);flex-wrap:wrap}
.jscope-wrap .jscope{flex:1 1 280px}
.jscope-edit{flex:none;margin-top:2px}
.jscope-in{width:100%;min-height:96px;font:inherit;font-size:16px;line-height:1.5;color:var(--ink);
  background:var(--white);border:1px solid #D3C8B9;border-radius:var(--r3);padding:10px 12px;box-sizing:border-box;resize:vertical}
.jscope-acts{display:flex;gap:var(--s2)}
.jscope-acts .sys-b,.jscope-edit,.jscope-add{min-height:44px}
.nj-tick{width:20px;height:20px;flex:none;display:grid;place-items:center;border-radius:5px;
  background:var(--ink);color:#fff;font-style:normal;font-size:13px;font-weight:800}
.nj-rename{min-height:36px}
.nj-more{min-height:44px}
.nj-chips[hidden]{display:none}

/* A group's heading can carry its own action (The job → Change), and the
   group's body is one box the editor can replace in place (owner, 29 Sep). */
.jgroup-top{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);min-width:0}
.jgroup-in{display:flex;flex-direction:column;gap:var(--s5);min-width:0}
.jchange{min-height:44px;flex:none}
.jchange[hidden]{display:none}
.jstate{all:unset;cursor:pointer;display:inline-flex;align-items:center;min-height:44px;border-radius:99px}
.jstate:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.jedit{display:flex;flex-direction:column;gap:var(--s4)}
.je-sec{display:flex;flex-direction:column;gap:var(--s2);padding-top:var(--s3);border-top:1px solid var(--line)}
.je-sec:first-child{border-top:0;padding-top:0}
.je-sec h3{margin:0;font-size:14px;font-weight:800;color:var(--ink)}
.je-sec .nj-f:first-of-type{margin-top:0}
.je-sec .nj-when + .nj-chips{margin-top:var(--s2)}
.je-clear{align-self:flex-start;min-height:40px}
.je-acts{padding-top:var(--s2)}
.jedit select,.jedit input[type=text],.jedit input[type=date],.jedit input[type=time],.jedit textarea{
  width:100%;min-height:44px;font:inherit;font-size:15px;color:var(--ink);background:var(--white);
  border:1px solid #D3C8B9;border-radius:var(--r3);padding:10px 12px;box-sizing:border-box}
.jedit textarea{min-height:96px;resize:vertical;line-height:1.45}
/* The deposit, in Charges and payment (29 Sep): one line, and the decision
   beside it when the terms leave one. */
.jdep{margin:var(--s2) 0 0;padding:10px 12px;border:1px solid var(--line);border-radius:var(--r3);background:var(--cream-2)}
.jdep p{margin:0;font-size:14.5px;color:var(--ink)}
.jdep.decide{border-color:#D8A15A;background:#FFF6E8}
.jdep-why{margin-top:4px !important;color:#4A423B !important;font-size:14px !important}
.jdep .jacts{margin-top:var(--s2)}
.jdep-terms{margin-top:6px}
.jdep-terms summary{cursor:pointer;font-size:13.5px;font-weight:700;color:#4A423B;min-height:32px;display:flex;align-items:center}
.jdep-terms ul{margin:4px 0 0;padding-left:18px;font-size:13.5px;line-height:1.5;color:#4A423B}
.nj-dep{margin-top:var(--s3);padding:10px 12px;border:1px solid var(--line);border-radius:var(--r3);background:var(--cream-2);font-size:14px;color:var(--ink)}
.nj-dep[hidden]{display:none}
.nj-dep label{display:flex;align-items:center;gap:10px;min-height:44px;margin-top:4px;font-weight:600;cursor:pointer}
.nj-dep input{width:20px;height:20px;accent-color:var(--ink)}
.nj-dep .nj-hint{margin-top:2px}
.nj-dep .nj-depreq span{margin-left:auto;font-weight:700;color:var(--ink-2, var(--ink))}

/* ── the job page has surfaces (owner, 29 Sep: "so washed out") ─────────────
   The text was already ink; what read as faded was that the job and the work
   sat straight on the cream, only the rail had a card, controls had borders
   the colour of the background, and the working facts were 12-13px. Every
   group is now a white card on the cream - the job, what needs doing, the
   work, charges, next, and the folded record - with a firm edge, and the
   facts and controls a size you read at arm's length. Still restrained:
   white, ink and one orange. */
.jobgrid .jobcol{display:flex;flex-direction:column;gap:14px;min-width:0}
.jobgrid .jobpart,
.jobgrid .jobpart:not(.is-first),
.jobgrid .jobpart.is-first{background:var(--white);border:1px solid #DDD2C3;border-radius:16px;
  padding:20px 22px;box-shadow:0 1px 3px rgba(26,22,19,.06)}
@media (min-width:1100px){
  .jobgrid--rail:not(.jobgrid--one) .jobcol--side{background:none;border:0;border-radius:0;padding:0;
    display:flex;flex-direction:column;gap:14px}
  .jobgrid--rail:not(.jobgrid--one) .jobcol--main > .jobpart:first-child{padding-top:20px}
}
.jobgrid--one{gap:12px}
@media (max-width:699px){
  .jobgrid{gap:12px}
  .jobgrid .jobpart,
  .jobgrid .jobpart:not(.is-first),
  .jobgrid .jobpart.is-first{padding:16px;border-radius:14px}
}
.jobgrid .jobbrief{margin-bottom:2px}

/* the folded record, as one card */
.jobfoot{margin-top:14px;border-top:0;background:var(--white);border:1px solid #DDD2C3;border-radius:16px;
  padding:0 22px;box-shadow:0 1px 3px rgba(26,22,19,.06)}
.jobfoot .jfold:last-child{border-bottom:0}
@media (max-width:699px){ .jobfoot{padding:0 16px;border-radius:14px} }

/* the working facts, readable */
.jobgrid .facts .fact > span{font-size:13.5px}
.jobgrid .facts .fact > b{font-size:15px}
/* controls you can see the edge of */
.jobgrid .sys-b.quiet, .jobbrief .sys-b.quiet, .jobfoot .sys-b.quiet{border-color:#CFC3B2}
.jobgrid .sys-b.quiet.thin, .jobbrief .sys-b.quiet.thin{font-size:13px}
.jobgrid textarea, .jobgrid input[type=text]{border-color:#CFC3B2}
/* What they told us: the question in the secondary ink, not a pale grey;
   the file line not faded to 70% (29 Sep). */
.jgroup .toldrow > span:first-child, .jgroup .toldrow .q{color:#4A423B;opacity:1}
.jgroup .toldfile{opacity:1;color:#4A423B}
.jgroup .asked{color:#4A423B}
/* 29 Sep cleanup: an empty Next is a quiet line; what needs doing is rows */
.jobgrid .jobpart.is-quiet{background:none;border:0;box-shadow:none;padding:0 4px}
.jnext-quiet .sys-b{min-height:44px;padding-left:0;font-weight:700;color:#4A423B}
.duelist{display:flex;flex-direction:column;gap:2px}
.duelist .frow .n i{display:block;font-style:normal;font-size:13px;font-weight:600;color:#8A4A12}
.qwho .qdep{display:block;margin-top:3px;font-size:12.5px;font-weight:700;color:#8A4A12}
/* A booking held for its deposit (29 Sep): dashed and warm - held, not booked. */
.block.b-held,.wchip.b-held{background:#FFF6E8;border:1.5px dashed #C98A2E;color:var(--ink)}
.block .heldtag{display:inline-block;margin-top:2px;font-size:11px;font-weight:800;color:#8A4A12;letter-spacing:.02em}
.lg-held{display:inline-block;width:10px;height:10px;border:1.5px dashed #C98A2E;background:#FFF6E8;border-radius:2px}
/* Book the next one (29 Sep) */
.jrebook{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);flex-wrap:wrap}
.jrebook p{margin:0;font-size:14.5px;color:var(--ink)}
.jrebook-b{width:100%;min-height:48px;font-weight:800}
.jnext-add{margin-top:var(--s2);min-height:44px;padding-left:0;font-weight:700;color:#4A423B}
.rbk{display:flex;flex-direction:column;gap:var(--s3)}
.rb-what{margin:0;font-size:15px;font-weight:700;color:var(--ink)}
.rb-weeks .nj-chip{min-width:88px}
.rb-times{display:flex;flex-direction:column;gap:var(--s3);min-height:80px}
.rb-day h4{margin:0 0 6px;font-size:14px;font-weight:800;color:var(--ink)}
.rb-day h4 i{font-style:normal;font-weight:700;color:#8A4A12}
.rb-slots{display:flex;flex-wrap:wrap;gap:6px}
.rb-slot{min-width:76px}
.jrebook .jrebook-b{background:var(--white);border:1.5px solid var(--ink);border-radius:999px;color:var(--ink);font-size:15px}
.jrebook .jrebook-b:hover{background:var(--cream-2)}
.jgroup .jnext-add{display:block;width:auto;align-self:flex-start;text-align:left}
.rb-days{margin-bottom:var(--s2)}
.rb-days .nj-chip{min-width:92px}
.rb-tell{display:flex;flex-direction:column;gap:6px}
.rb-tell .nj-hint{margin:0}

/* How customers can pay (30 Sep): rows shaped like the card's .srow rows,
   inside the card's .sched inset - not flush to its edges. */
.paywaylist{padding:0 14px 14px;display:flex;flex-direction:column;gap:7px}
.wayrow{display:flex;align-items:center;gap:14px;padding:13px 15px 13px 16px;border-radius:var(--r2);
  background:var(--cream-2);position:relative;overflow:hidden}
.wayrow:before{content:'';position:absolute;left:0;top:10px;bottom:10px;width:3px;border-radius:3px;background:var(--line)}
.wayrow.on:before{background:var(--mint-d)}
.waytext{flex:1;display:flex;flex-direction:column;gap:3px;min-width:0}
.waytext b{font-size:14.5px;font-weight:700;letter-spacing:-.012em;color:var(--ink)}
.waytext span{font-size:12.5px;color:var(--grey);font-weight:600;line-height:1.45}
.waytext .wayfee{color:var(--ink);font-weight:600}
.waystate{font-weight:700}
.waystate.ws-active{color:#1D7A4B}
.waytg{flex:none;min-width:64px;min-height:44px;border-radius:99px;border:1.5px solid var(--line);background:var(--white);
  font-weight:800;font-size:14px;color:var(--grey);cursor:pointer}
.waytg.on{background:var(--ink);border-color:var(--ink);color:var(--white)}
.waytg:disabled{opacity:.5;cursor:default}
