/* manolo — the site's one stylesheet.
   Every page shares it, so a token or a component is defined once. The tokens are the app's own
   globals.css values; see sites/official/definitions/direction.md, which is the contract this file
   implements. Served from /static/ by main.py under `style-src 'self' 'unsafe-inline'`.
*/
/* ── self-hosted brand faces (Archivo · IBM Plex Sans · IBM Plex Mono) ── */
@font-face{font-family:'Archivo';font-style:normal;font-weight:600;font-display:swap;src:url(/static/fonts/archivo-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Archivo';font-style:normal;font-weight:700;font-display:swap;src:url(/static/fonts/archivo-700.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Archivo';font-style:normal;font-weight:800;font-display:swap;src:url(/static/fonts/archivo-800.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url(/static/fonts/plex-sans-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url(/static/fonts/plex-sans-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url(/static/fonts/plex-sans-600.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(/static/fonts/plex-mono-400.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(/static/fonts/plex-mono-500.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

/* ── tokens ────────────────────────────────────────────────────────────────────
   The page is dark and the app is not, and that is the whole shape of this block. Two sets:
   this one is the SITE's — charcoal ground, amber accent — and `--ap-*` on `.phone` is the APP's,
   which keeps iOS's light grouped-table ground because that is what the phone actually draws.
   The two share only the accent hue, so a frame reads as a lit screen on a dark page rather than
   as a panel cut out of it.

   Raw tokens name their ROLE, not their colour: a token called `--c-green` holding amber is the
   bug that a rename is cheaper than. Aliases below are what components use. */
:root{
  --c-paper:#14161b; --c-paper-sunk:#1b1e25; --c-card:#232830;
  --c-ink:#eff1f4; --c-ink-soft:#c0c6d0; --c-muted:#8a929e; --c-hairline:#2e343d;
  /* `-lift` and not `-deep`: on a dark ground the emphatic accent is LIGHTER than the accent,
     and it does double duty as hover fill and as text on `--c-accent-tint`. */
  --c-accent:#f2a541; --c-accent-lift:#ffbe6b; --c-accent-tint:#3a2c18; --c-accent-line:#4d3b1f;
  --c-on-accent:#1a1408;
  /* the advisory colour — what manolo noticed but will not block on */
  --c-flag:#e5b45c; --c-flag-tint:#372c16; --c-flag-ink:#f6d9a2;
  --bg:var(--c-paper); --bg-sunk:var(--c-paper-sunk); --surface:var(--c-card);
  --text:var(--c-ink); --text-soft:var(--c-ink-soft); --text-muted:var(--c-muted);
  --line:var(--c-hairline); --accent:var(--c-accent); --accent-lift:var(--c-accent-lift); --accent-tint:var(--c-accent-tint);
  --accent-line:var(--c-accent-line); --on-accent:var(--c-on-accent);
  --flag:var(--c-flag); --flag-tint:var(--c-flag-tint); --flag-ink:var(--c-flag-ink);
  --f-display:'Archivo',ui-sans-serif,system-ui,-apple-system,sans-serif;
  --f-body:'IBM Plex Sans',ui-sans-serif,system-ui,-apple-system,sans-serif;
  --f-mono:'IBM Plex Mono',ui-monospace,'SF Mono',Menlo,monospace;
  --r-card:12px; --r-sm:10px; --r-round:999px;
  --sh-1:0 1px 2px rgba(0,0,0,.30), 0 2px 8px rgba(0,0,0,.22);
  --sh-2:0 6px 16px rgba(0,0,0,.34), 0 18px 40px rgba(0,0,0,.40);
  --ease-out:cubic-bezier(.23,1,.32,1);
  --ease-out-expo:cubic-bezier(.16,1,.3,1);
  --z-nav:50;
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%; scroll-behavior:smooth}
body{
  margin:0; background:var(--bg); color:var(--text);
  font-family:var(--f-body); font-size:16px; line-height:1.55;
  font-weight:400; -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img{max-width:100%; display:block}
h1,h2,h3{font-family:var(--f-display); line-height:1.08; letter-spacing:-.02em; margin:0; text-wrap:balance; color:var(--text)}
p{margin:0; text-wrap:pretty}
a{color:inherit}
button{font:inherit; color:inherit}

/* ── layout ── */
.wrap{width:100%; max-width:1120px; margin-inline:auto; padding-inline:clamp(20px,5vw,40px)}
main{display:block}
section{position:relative}
.sec{padding-block:clamp(44px,5.5vw,72px)}
main > section + section{border-top:1px solid var(--line)}
main > section:nth-of-type(even){background:var(--bg-sunk)}

/* focus + skip */
:where(a,button,input,[tabindex]):focus-visible{outline:2.5px solid var(--accent); outline-offset:3px; border-radius:4px}
.skip{position:fixed; top:10px; left:10px; z-index:100; background:var(--surface); color:var(--text);
  padding:10px 16px; border-radius:var(--r-sm); transform:translateY(-260%); transition:transform .18s var(--ease-out)}
.skip:focus{transform:translateY(0); box-shadow:var(--sh-2)}

/* ── header / nav ── */
.nav{position:sticky; top:0; z-index:var(--z-nav); background:rgba(20,22,27,.82);
  backdrop-filter:saturate(140%) blur(10px); border-bottom:1px solid var(--line)}
@supports not (backdrop-filter:blur(1px)){.nav{background:var(--bg)}}
.nav-in{display:flex; align-items:center; justify-content:space-between; height:64px}
.brand{display:inline-flex; align-items:center; gap:10px; text-decoration:none; font-family:var(--f-display); font-weight:700; font-size:20px; letter-spacing:-.02em; color:var(--text)}
/* the app's own icon, tile and glove both drawn by the symbol; the page only rounds its corners */
.brand .mark{width:30px; height:30px; border-radius:9px; overflow:hidden; box-shadow:var(--sh-1); flex:0 0 auto}
.brand .mark svg{display:block; width:100%; height:100%}
.btn{
  display:inline-flex; align-items:center; gap:8px; font-family:var(--f-display); font-weight:600; font-size:15px;
  padding:11px 18px; border-radius:var(--r-sm); border:1px solid transparent; cursor:pointer; text-decoration:none;
  background:var(--accent); color:var(--on-accent); transition:transform .16s var(--ease-out), background-color .18s ease, box-shadow .18s ease;
  min-height:44px; box-shadow:var(--sh-1); touch-action:manipulation;
}
.btn .ic{width:17px; height:17px}
.btn:active{transform:scale(.97)}
@media (hover:hover) and (pointer:fine){ .btn:hover{background:var(--accent-lift); box-shadow:var(--sh-2)} }
.nav .btn{padding:9px 16px; min-height:44px}
.btn-big{min-height:52px; padding:14px 24px; font-size:16.5px}

/* ── hero ── */
.hero{padding-top:clamp(26px,4vw,48px); padding-bottom:clamp(34px,5vw,64px)}
.hero-grid{display:grid; grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr); gap:clamp(28px,4vw,56px); align-items:center}
.hero h1{font-weight:800; font-size:clamp(2.2rem,1.35rem+3.4vw,3.4rem); letter-spacing:-.035em; margin:16px 0 0; max-width:24ch}
.hero .lede{font-size:clamp(1.05rem,1rem+.4vw,1.22rem); color:var(--text-soft); max-width:36ch; margin-top:14px}
.hero .lede b{font-weight:600; color:var(--text)}
.cta-row{display:flex; align-items:center; gap:18px; margin-top:28px; flex-wrap:wrap}

/* Phone frames use the app's light grouped ground, white cards and system typeface.
   Use tabular figures; only the pictured receipt uses mono. The frame accent has
   enough contrast on white and is independent of the page accent. */
.phone, .readback, .stripcut, .travelcut{
  --ap-bg:#f2f2f5; --ap-card:#ffffff; --ap-high:#e7e7ea; --ap-highest:#dcdce0;
  --ap-ink:#1c1c1e; --ap-ink-2:#68686e; --ap-line:#d6d6db;
  --ap-accent:#a8631a; --ap-accent-c:#f8e6cd; --ap-accent-ink:#7a4407;
  /* the flag stays clearly redder than the accent, or "needs a look" and "do this"
     become the same colour and the board stops saying anything */
  --ap-flag:#a33a12; --ap-flag-c:#f9dfd4; --ap-flag-ink:#6d2408;
  --ap-red:#d70015; --ap-neutral-c:#e3e5e8; --ap-neutral-ink:#33363a;
  --ap-mint:#e0b98a;
  --ap-outline:#a5a5aa;
  /* Answer on the app's ringing strip (`callAnswer`, mobile/theme/mockupStyles.ts), and the two
     buttons Android's own call notification draws, in Android's own colours */
  --ap-answer:#1f7a3d; --os-answer:#1e8e3e; --os-decline:#d93025;
  --ap-r:12px; --ap-r-s:6px;
  --f-app:-apple-system,'SF Pro Text','Segoe UI',Roboto,system-ui,sans-serif;
}
.num{font-variant-numeric:tabular-nums}
.phone-col{display:flex; flex-direction:column; align-items:center}
.phone{width:300px; max-width:100%; margin-inline:auto; background:#3a4049; border-radius:38px; padding:9px; box-shadow:var(--sh-2)}
/* real-phone proportions: every screen is at least as tall as a ≈390×844 phone scaled to this
   frame (min-height, not a hard ratio, so a content-heavy frame grows instead of clipping);
   the tab bar pins to the bottom and the paper fills the middle, as on the device */
.phone .screen{background:var(--ap-bg); border-radius:30px; overflow:hidden; position:relative;
  border:1px solid rgba(0,0,0,.06); display:flex; flex-direction:column; min-height:595px;
  font-family:var(--f-app); color:var(--ap-ink)}

/* The status bar and the camera cutout. The app draws neither — the OS owns both — but a frame
   that leaves them off is a frame with its title where the notch is. */
.ap-status{display:flex; justify-content:space-between; align-items:center; height:30px; padding:0 15px;
  font:500 11px/1 var(--f-app); font-variant-numeric:tabular-nums; color:var(--ap-ink)}
.ap-status-right{display:flex; align-items:center; gap:5px}
.ap-status svg{display:block}
.ap-island{position:absolute; top:8px; left:50%; transform:translateX(-50%); width:66px; height:18px;
  border-radius:var(--r-round); background:#000; z-index:3}

/* top bar: the title is CENTRED and the bar carries a hairline under it. The frames drew Material's
   large left-aligned title for months, which is the Android layout on a page whose screenshots are
   iOS. The three columns are equal-weight so the title stays centred on the SCREEN, not centred in
   whatever space the icons left over. */
.ap-topbar{display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:8px;
  padding:1px 11px 8px; border-bottom:1px solid var(--ap-line)}
.ap-title{text-align:center; font:600 15px/20px var(--f-app); letter-spacing:-.01em; white-space:nowrap}
.ap-avatar{width:28px; height:28px; border-radius:50%; background:var(--ap-flag-c); color:var(--ap-flag-ink);
  display:grid; place-items:center; font:600 10.5px/1 var(--f-app); justify-self:start}
.ap-iconbtn{width:26px; height:26px; display:grid; place-items:center; color:var(--ap-accent); justify-self:end}
.ap-iconbtn svg{width:18px; height:18px}
/* Contacts' close and keypad: the plain icon button, in the quiet ink rather than the accent */
.ap-iconbtn.quiet{color:var(--ap-ink-2)}
/* the conversation's two trailing controls: which job it is showing, and the call back */
.ap-trailing{display:flex; align-items:center; gap:6px; justify-self:end}
.ap-trailing .ap-chip{margin-top:0}
/* the conversation's header: who, over the number, still centred */
.ap-titlestack{min-width:0; text-align:center}
.ap-titlestack b{display:block; font:600 14px/18px var(--f-app); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-titlestack i{display:block; font:400 11px/15px var(--f-app); font-style:normal; color:var(--ap-ink-2);
  font-variant-numeric:tabular-nums}
/* the back affordance is a labelled chevron in the accent, left of the name */
.ap-back{display:inline-flex; align-items:center; gap:1px; color:var(--ap-accent);
  font:500 12.5px/16px var(--f-app); justify-self:start; white-space:nowrap}
.ap-back svg{width:13px; height:13px}
/* the board's search field, which sits above the segments and is on screen at rest */
.ap-search{display:flex; align-items:center; gap:8px; background:var(--ap-high); border-radius:9px;
  padding:8px 11px; font:400 11.5px/16px var(--f-app); color:var(--ap-ink-2)}
.ap-search svg{width:13px; height:13px; flex:0 0 auto}

/* the scrolling middle: everything the app draws between the bars */
.ap-body{flex:1; min-height:0; display:flex; flex-direction:column; gap:8px; padding:9px 11px 12px}
.ap-body.thread{gap:11px}

/* segmented control — a sunken grey track with the chosen segment raised out of it as a white
   pill. Not an outlined-and-divided bar with a tick in it, which is Material's. */
.ap-seg{display:flex; gap:2px; background:var(--ap-high); border-radius:8px; padding:2px}
.ap-seg span{flex:1 1 0; display:inline-flex; align-items:center; justify-content:center; gap:5px;
  padding:5px 6px; border-radius:6px; font:500 11px/16px var(--f-app); color:var(--ap-ink); white-space:nowrap}
.ap-seg span.on{background:var(--ap-card); font-weight:600; box-shadow:0 1px 2px rgba(0,0,0,.12)}
/* a mode the composer is not offering as live: Private note with no job selected has nothing to
   file a note against, and the app never draws a live-looking control that would refuse the tap */
.ap-seg span.off{opacity:.45}
.ap-seg span.unread::after{content:""; width:5px; height:5px; border-radius:50%; background:var(--ap-accent)}

/* a record on the board: the docket tile, what it is, and where it got to */
.ap-list{display:flex; flex-direction:column; gap:8px}
.ap-item{position:relative; display:grid; grid-template-columns:auto minmax(0,1fr); gap:11px; align-items:start;
  min-height:52px; padding:10px; background:var(--ap-card); border-radius:var(--ap-r)}
/* Unread reads in the trailing gutter and in the headline weight. It sits right because the left
   is the docket's — a dot beside a tinted tile reads as part of the tile, not as a state of the row. */
.ap-item.unread{padding-right:20px}
.ap-item.unread::after{content:""; position:absolute; right:8px; top:50%; transform:translateY(-50%);
  width:7px; height:7px; border-radius:50%; background:var(--ap-accent)}
.ap-item.unread .ap-item-head{font-weight:700}
/* The tile is tinted by what the row IS, and the app has only two tints for it: the accent on the
   job the clock is on (`Docket tone="live"`, mobile/jobs/JobRow.tsx) and the flag on a bill that
   wants a look before it is filed (`tone="attention"`, mobile/money/BillRow.tsx). There is no
   amber job tile — the frames drew one for "waiting on an answer" and the app has never had it. */
.ap-docket{width:38px; padding:4px 0 5px; border-radius:var(--ap-r-s); background:var(--ap-highest);
  color:var(--ap-ink-2); display:grid; place-items:center; text-align:center}
.ap-docket i{font-style:normal; font:600 8px/11px var(--f-app); letter-spacing:.04em}
.ap-docket b{font:700 12.5px/16px var(--f-app); color:var(--ap-ink); font-variant-numeric:tabular-nums}
.ap-docket.amber{background:var(--ap-flag-c); color:var(--ap-flag-ink)}
.ap-docket.amber b{color:var(--ap-flag-ink)}
.ap-docket.green{background:var(--ap-accent-c); color:var(--ap-accent-ink)}
.ap-docket.green b{color:var(--ap-accent-ink)}
.ap-item-body{min-width:0; display:flex; flex-direction:column; align-items:flex-start; gap:3px}
.ap-item-head{max-width:100%; font:500 12.5px/16px var(--f-app); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-item-sub{max-width:100%; font:400 10.5px/14px var(--f-app); color:var(--ap-ink-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-item-foot{display:flex; align-items:center; gap:8px; margin-top:6px}
.ap-item-foot .ap-chip{margin-top:0}
.ap-item-foot b{font:600 13px/16px var(--f-app); font-variant-numeric:tabular-nums}
/* chip — a state you can change, so it carries its own caret */
.ap-chip{display:inline-flex; align-items:center; gap:5px; margin-top:7px; padding:3px 9px; border-radius:var(--r-round);
  border:1px solid var(--ap-line); color:var(--ap-ink); font:500 10px/14px var(--f-app); white-space:nowrap}
.ap-chip i{font-style:normal; font-size:8px; opacity:.7}
.ap-chip.amber{background:var(--ap-flag-c); color:var(--ap-flag-ink); border-color:transparent}
.ap-chip.green{background:var(--ap-accent-c); color:var(--ap-accent-ink); border-color:transparent}
.ap-chip.solid{background:var(--ap-neutral-c); color:var(--ap-neutral-ink); border-color:transparent;
  font-size:8.5px; letter-spacing:.05em}
/* group label on the Money board: the zone and its total, ruled off */
.ap-group{display:flex; align-items:center; gap:7px; margin:3px 0 0; font:500 9.5px/14px var(--f-app);
  letter-spacing:.06em; text-transform:uppercase; color:var(--ap-ink-2)}
.ap-group::after{content:""; flex:1; height:1px; background:var(--ap-line)}

/* buttons — the app's, in the four weights the frames need */
.ap-btn{display:inline-flex; align-items:center; justify-content:center; min-height:30px; padding:0 16px;
  border-radius:var(--r-round); background:var(--ap-accent); color:#fff; font:500 11.5px/1 var(--f-app);
  white-space:nowrap; flex:0 0 auto}
.ap-btn.outlined{background:transparent; color:var(--ap-accent); border:1px solid var(--ap-accent)}
.ap-btn.text{background:transparent; color:var(--ap-accent); padding:0 8px}
.ap-btn.tonal-green{background:var(--ap-accent-c); color:var(--ap-accent-ink)}
/* the weight the app keeps for the control that ends something: Hang up on a live call, Discard
   on a visit nothing can bring back. The one red the frames already carry, so it costs no colour */
.ap-btn.error{background:var(--ap-red)}
.ap-btn.answer{background:var(--ap-answer)}
/* the floating action, over the list rather than in the bar above it — a FILLED pill, which is
   what the app draws; the tonal one here was Material's */
.ap-fab{position:absolute; right:12px; bottom:66px; z-index:2; display:inline-flex; align-items:center; gap:7px;
  min-height:40px; padding:0 17px; border-radius:var(--r-round); background:var(--ap-accent); color:#fff;
  font:600 12px/40px var(--f-app); box-shadow:0 3px 10px rgba(0,0,0,.22)}
.ap-fab svg{width:15px; height:15px}

/* the job's brief, above the conversation: what it is, where it is, and the clock */
.ap-brief{background:var(--ap-card); border-radius:var(--ap-r); overflow:hidden}
.ap-brief-head{display:flex; align-items:center; gap:8px; padding:9px 11px}
.ap-brief-num{color:var(--ap-accent); font:600 11.5px/16px var(--f-app); font-variant-numeric:tabular-nums; flex:0 0 auto}
.ap-brief-title{flex:1; min-width:0; font:500 12px/16px var(--f-app); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-brief-row{display:flex; align-items:center; gap:8px; padding:8px 11px; box-shadow:inset 0 1px 0 var(--ap-line);
  font:400 11.5px/16px var(--f-app)}
.ap-brief-row > span{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-brief-row svg{width:14px; height:14px; color:var(--ap-ink-2); flex:0 0 auto}
/* the clock label wraps rather than truncates: at 300px the two buttons beside it own the row */
.ap-brief-row > .ap-brief-k{flex:1; color:var(--ap-ink-2); white-space:normal; line-height:14px}
.ap-chev{color:var(--ap-ink-2); font-size:15px; margin-left:auto; flex:0 0 auto}
.ap-brief-row .ap-btn{min-height:26px; padding:0 10px}

/* thread: chips ride above the bubble, the way the app files a message before it shows it */
.ap-msg{display:flex; flex-direction:column; gap:4px; max-width:86%; align-self:flex-start}
.ap-msg.out{align-self:flex-end; align-items:flex-end}
.ap-chips{display:flex; align-items:center; gap:5px; flex-wrap:wrap}
.ap-chips span{padding:2px 6px; border-radius:var(--r-round); border:1px solid var(--ap-line);
  color:var(--ap-ink-2); font:500 8.5px/13px var(--f-app); letter-spacing:.03em}
.ap-chips .jc{color:var(--ap-accent)}
.ap-chips .pv{background:var(--ap-flag-c); color:var(--ap-flag-ink); border-color:transparent}
.ap-bubble{padding:9px 11px; border-radius:16px; border-bottom-left-radius:4px; background:var(--ap-card);
  color:var(--ap-ink); font:400 12px/17px var(--f-app)}
.ap-msg.out .ap-bubble{border-bottom-left-radius:16px; border-bottom-right-radius:4px}
/* what you sent is tinted, what came in is white — the tail alone is too quiet to say who spoke.
   A private note keeps its own amber: it went to nobody. */
.ap-msg.out .ap-bubble:not(.note){background:var(--ap-accent-c); color:var(--ap-accent-ink)}
.ap-bubble p{margin:0}
.ap-bubble.note{background:var(--ap-neutral-c); color:var(--ap-neutral-ink); border-radius:var(--ap-r)}
.ap-bubble.photo{padding:5px}
.ap-bubble.photo img{width:186px; height:116px; object-fit:cover; object-position:50% 46%; border-radius:8px; display:block}
.ap-audio{display:flex; align-items:center; gap:9px; margin-top:9px}
.ap-audio .pl{width:22px; height:22px; border-radius:50%; background:var(--ap-accent); display:grid; place-items:center; flex:0 0 auto}
.ap-audio .pl svg{width:10px; height:10px; color:#fff}
.ap-audio .trk{flex:1; height:3px; border-radius:2px; background:rgba(28,28,30,.2); position:relative}
.ap-audio .trk::after{content:""; position:absolute; inset:0 62% 0 0; border-radius:2px; background:var(--ap-ink)}
.ap-audio .tm{font:400 9.5px/1 var(--f-app); color:var(--ap-ink-2); font-variant-numeric:tabular-nums}
.ap-time{font:400 9.5px/13px var(--f-app); color:var(--ap-ink-2); font-variant-numeric:tabular-nums}
.ap-more{display:inline-block; margin-top:7px; font:500 11px/1 var(--f-app); color:var(--ap-ink-2)}
.ap-more::after{content:" \25BE"; font-size:8px}
/* the card manolo raises when it needs a thumb: outlined in the "needs you" colour, never filled,
   so it reads as an ask rather than as something already done */
.ap-approval{background:var(--ap-card); border:1px solid var(--ap-flag); border-radius:var(--ap-r); padding:11px}
.ap-ask{margin:0 0 3px; font:600 12.5px/17px var(--f-app)}
.ap-from{margin:0 0 9px; font:400 10.5px/14px var(--f-app); color:var(--ap-ink-2)}
.ap-from b{color:var(--ap-ink); font-weight:600}
.ap-slot{display:flex; align-items:center; gap:8px; padding:7px 9px; border-radius:8px;
  background:var(--ap-accent-c); color:var(--ap-accent-ink); font:600 11.5px/16px var(--f-app)}
.ap-slot svg{width:14px; height:14px; flex:0 0 auto}
.ap-dur{margin-top:9px}
.ap-lab{font:500 10.5px/14px var(--f-app); color:var(--ap-ink-2)}
.ap-step{display:flex; align-items:center; gap:7px; margin-top:5px}
.ap-step .st{width:28px; height:26px; display:grid; place-items:center; border:1px solid var(--ap-line);
  border-radius:var(--r-round); color:var(--ap-ink); font-size:14px; line-height:1}
.ap-step .val{flex:1; text-align:center; font:600 12.5px/1 var(--f-app); font-variant-numeric:tabular-nums}
.ap-acts{display:flex; gap:8px; margin-top:11px}
.ap-acts .ap-btn:first-child{flex:1}

/* composer: one rounded field carrying its own actions, send as a peer of equal height */
.ap-composer{margin-top:auto; border-top:1px solid var(--ap-line);
  padding:8px 11px 10px; display:flex; flex-direction:column; gap:8px}
.ap-composer-row{display:flex; align-items:center; gap:7px}
.ap-field{flex:1; min-width:0; display:flex; align-items:center; gap:4px; padding:0 8px 0 11px; min-height:34px;
  border-radius:var(--r-round); background:var(--ap-highest)}
.ap-field .ph{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font:400 11.5px/1 var(--f-app); color:var(--ap-ink-2)}
.ap-field .ci{width:17px; height:17px; color:var(--ap-ink-2); flex:0 0 auto}
.ap-send{width:34px; height:34px; border-radius:50%; background:var(--ap-accent); display:grid; place-items:center; flex:0 0 auto}
.ap-send svg{width:16px; height:16px; color:#fff}

/* scheduling: one card per day, today tinted, the run reading top to bottom */
.ap-day{background:var(--ap-card); border-radius:var(--ap-r); padding:9px 11px; display:flex; flex-direction:column; gap:8px}
.ap-day.today{background:var(--ap-accent-c); color:var(--ap-accent-ink)}
.ap-day-head{display:flex; align-items:center; gap:7px}
.ap-day-head b{font:600 13px/17px var(--f-app)}
.ap-day-head span{font:400 11px/16px var(--f-app); color:var(--ap-ink-2)}
.ap-day.today .ap-day-head span{color:inherit; opacity:.85}
.ap-day.today .ap-chip.solid{color:var(--ap-neutral-ink); opacity:1}
.ap-plus{margin-left:auto; font-size:16px; line-height:1; color:var(--ap-ink-2)}
.ap-day.today .ap-plus{color:inherit}
.ap-booking{display:flex; align-items:center; gap:10px; padding:7px 9px; border-radius:8px; background:var(--ap-bg)}
.ap-day.today .ap-booking{background:rgba(255,255,255,.55)}
/* one fixed-width time column so every booking's digits line up down the day run */
.ap-booking-time{flex:0 0 48px; display:flex; flex-direction:column; gap:1px; align-items:flex-end; font-variant-numeric:tabular-nums}
.ap-booking-time b{display:flex; align-items:baseline; gap:2px; font:600 10.5px/14px var(--f-app)}
.ap-booking-time i{font:500 8px/12px var(--f-app); font-style:normal; opacity:.7; width:11px; text-align:left}
.ap-booking-what{min-width:0; display:flex; flex-direction:column; gap:1px}
.ap-booking-what span{font:500 11.5px/15px var(--f-app); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-booking-what .sub{font:400 10px/14px var(--f-app); opacity:.75}
.ap-empty{margin:0; font:400 11px/16px var(--f-app); color:var(--ap-ink-2)}
.ap-day.today .ap-empty{color:inherit; opacity:.8}

/* a calendar entry read out of your own calendar: shown, never yours to move — so it is
   outlined rather than filled, and says where it came from */
.ap-booking.ext{background:transparent; border:1px dashed var(--ap-line); color:var(--ap-ink-2)}
.ap-booking.ext .ap-booking-what > span:first-child{color:var(--ap-ink-2); font-weight:400}
.ap-booking.ext .sub{display:flex; align-items:center; gap:4px}
.ap-booking.ext .gcal{width:9px; height:9px; flex:0 0 auto}

/* items: which job you're adding to, that job's lines, then the price book */
.ap-sect{margin:0; font:600 12.5px/17px var(--f-app)}
.ap-pickrow{display:flex; gap:8px}
.ap-pick{flex:1; min-width:0; padding:8px 9px; border:1px solid var(--ap-line); border-radius:var(--ap-r); background:var(--ap-card)}
.ap-pick b{display:block; font:500 11px/15px var(--f-app); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-pick span{display:block; margin-top:1px; font:400 10px/14px var(--f-app); color:var(--ap-ink-2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-pick.on{background:var(--ap-accent-c); border-color:var(--ap-accent); color:var(--ap-accent-ink)}
.ap-pick.on span{color:inherit; opacity:.85}
.ap-editor{padding:10px 11px; border:1px solid var(--ap-line); border-radius:var(--ap-r)}
.ap-editor-head{display:flex; align-items:baseline; gap:8px; margin-bottom:2px}
.ap-editor-head span{font:500 12.5px/17px var(--f-app)}
.ap-editor-head b{margin-left:auto; font:600 15px/20px var(--f-app); font-variant-numeric:tabular-nums}
.ap-line{display:flex; align-items:center; gap:8px; padding:7px 0; font:400 11.5px/16px var(--f-app)}
.ap-line .nm{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-line .crt{font-style:normal; font-size:8px; color:var(--ap-ink-2); flex:0 0 auto}
.ap-line .amt{font-size:10.5px; color:var(--ap-ink-2); white-space:nowrap}
.ap-line .bin{width:14px; height:14px; color:var(--ap-ink-2); flex:0 0 auto}
/* Open, the row's "2 × $18.00" is the same two numbers the fields below already hold. */
.ap-lineedit{display:flex; flex-wrap:wrap; align-items:flex-end; gap:8px; padding:2px 0 8px}
.ap-lineedit .fg{display:flex; flex-direction:column; gap:3px}
.ap-lineedit i{font-style:normal; font:400 9px/12px var(--f-app); color:var(--ap-ink-2)}
.ap-lineedit .fld{min-width:40px; padding:5px 7px; border:1px solid var(--ap-line); border-radius:6px;
  background:var(--ap-card); font:400 11px/15px var(--f-app)}
/* sell is worked out from cost and markup, never typed — the two can't drift apart */
.ap-lineedit .sell{margin-left:auto; text-align:right}
.ap-lineedit .sell b{display:block; font:600 15px/20px var(--f-app); font-variant-numeric:tabular-nums}
.ap-priced{display:flex; flex-direction:column; gap:7px; padding:9px 11px; background:var(--ap-card); border-radius:var(--ap-r)}
.ap-priced .nm{font:500 12px/16px var(--f-app)}
.ap-priced-foot{display:flex; align-items:center; gap:9px}
.ap-priced-foot .amt{font:600 12.5px/17px var(--f-app); font-variant-numeric:tabular-nums}
.ap-priced-foot .amt i{font-style:normal; font-weight:400; color:var(--ap-ink-2)}
.ap-priced-foot .ap-btn{margin-left:auto}
/* a supplier row carries what the price file says about the part, and what it costs you */
.ap-priced.two .meta{font:400 9.5px/13px var(--f-app); color:var(--ap-ink-2)}
.ap-priced .cost{display:flex; flex-direction:column; gap:1px}
.ap-priced .cost i{font-style:normal; font:400 9px/12px var(--f-app); color:var(--ap-ink-2)}
.ap-priced .cost b{font:600 12.5px/17px var(--f-app); font-variant-numeric:tabular-nums}

/* bottom tab bar: the active tab fills its icon and sits on a pill indicator, as Material's does.
   The bottom padding is not decoration — it is the room the gesture bar takes, and without it the
   labels sit under the bar the OS draws. */
.ap-nav{display:grid; grid-template-columns:repeat(4,1fr); margin-top:auto; padding:7px 2px 15px;
  background:var(--ap-card)}
.ap-home{position:absolute; left:50%; bottom:6px; transform:translateX(-50%); width:98px; height:4px;
  border-radius:var(--r-round); background:var(--ap-ink); opacity:.32; z-index:4}
.ap-nav span{display:flex; flex-direction:column; align-items:center; gap:2px; color:var(--ap-ink-2);
  font:500 9px/12px var(--f-app)}
.ap-nav span.on{color:var(--ap-ink)}
.ap-nav-ico{position:relative; display:grid; place-items:center; width:46px; height:23px;
  border-radius:var(--r-round); color:var(--ap-ink-2)}
.ap-nav span.on .ap-nav-ico{background:var(--ap-neutral-c); color:var(--ap-neutral-ink)}
.ap-nav-ico svg{width:19px; height:19px}
.ap-badge{position:absolute; top:-3px; right:5px; min-width:13px; height:13px; padding:0 3px; border-radius:var(--r-round);
  background:var(--ap-red); color:#fff; font:500 8.5px/13px var(--f-app); font-style:normal; text-align:center}
.cap{font-size:12.5px; color:var(--text-muted); text-align:center; margin-top:14px; font-family:var(--f-mono); max-width:300px}

/* ── the four jobs (JTBD ledger) ── */
.tour h2{font-size:clamp(1.7rem,1.3rem+1.6vw,2.4rem); font-weight:700; margin-top:14px; max-width:18ch}
.tour .body{font-size:1.06rem; color:var(--text-soft); max-width:56ch; margin-top:16px}
.ledger{margin-top:30px; background:var(--surface); border:1px solid var(--line); border-radius:var(--r-card); box-shadow:var(--sh-1); overflow:hidden}
.lg-row{display:grid; grid-template-columns:96px 1fr auto; gap:14px; padding:16px 18px; border-bottom:1px solid var(--line); align-items:center}
.lg-row:last-child{border-bottom:0}
.lg-row .t{font-family:var(--f-mono); font-weight:500; font-size:11px; letter-spacing:.05em; color:var(--text-muted); text-transform:uppercase}
.lg-row .q{font-size:15.5px; color:var(--text); line-height:1.5}
.lg-row .q i{font-style:normal; color:var(--text-soft)}
.lg-row .goto{display:inline-flex; align-items:center; gap:7px; font-family:var(--f-display); font-weight:600; font-size:12.5px; color:var(--accent-lift);
  background:var(--accent-tint); border:1px solid var(--accent-line); padding:10px 16px; border-radius:var(--r-round); white-space:nowrap; text-decoration:none; min-height:44px}
.lg-row .goto svg{width:13px; height:13px}
@media (hover:hover) and (pointer:fine){ .lg-row .goto:hover{background:var(--accent-tint)} .lg-row .goto:hover{border-color:var(--accent)} }

/* A heading breaks where its sentence breaks: each half is one unbreakable run, so the only
   place a line can end is the space between them. Released below 560px, where a long run would
   run off the screen (the media block at the foot of this sheet). */
.nb{white-space:nowrap}

/* ── tab chapters ── */
.chapter .ch-grid{display:grid; grid-template-columns:minmax(0,300px) 1fr; gap:clamp(30px,5vw,64px); align-items:center}
.chapter.flip .ch-grid{grid-template-columns:1fr minmax(0,300px)}
/* A TRIO is a chapter whose pictures take two columns instead of one: the words, then two picture
   columns. The clock chapter is one — its drive is as tall as its other two pictures together, so
   a single picture column ran 959px beside 297px of words — and the work number's two phones side
   by side are the other. The three share the
   width in proportion rather than pinning the pictures at 300px, because two pinned columns leave
   the words 242px at 1024. A flipped trio is the same weight as the rule above, so coming after it
   is what makes it win; an unflipped one puts its pictures first, so the wider column goes last. */
.chapter.trio .ch-grid{grid-template-columns:minmax(0,1.1fr) minmax(0,1fr) minmax(0,1fr);
  gap:clamp(20px,2.2vw,32px)}
.chapter.trio:not(.flip) .ch-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr) minmax(0,1.1fr)}
/* The two picture columns sit to the top, so "2 · Arrived" starts level with "1 · Start travel"
   and the pair reads as one row of panels; the words stay centred against the tallest of them. */
.chapter.trio .phone-col{align-self:start}
/* Every chapter writes its copy first, so a heading is met before the mockup it introduces. Side
   by side an unflipped chapter swaps the two back — the phone takes the left column — and that is
   the only thing `order` is for here: stacked, the document order is the reading order. */
.chapter:not(.flip) .phone-col{order:1}
.chapter:not(.flip) .ch-copy{order:2}
.chapter h1,.chapter h2{font-size:clamp(1.6rem,1.25rem+1.5vw,2.3rem); font-weight:700; margin-top:14px; max-width:40ch}
/* A chapter that opens a page carries the h1; it is set to what the h2 beside it renders at, so
   the office page's first title matches the rest (the clamp above is dropped by browsers: backlog B14). */
.chapter h1{font-size:1.5rem}
.chapter .scene{font-size:1.06rem; color:var(--text-soft); max-width:52ch; margin-top:16px}
.chapter .scene b{color:var(--text); font-weight:600}
.whatrows{margin-top:22px; display:grid}
.whatrow{display:grid; grid-template-columns:110px 1fr; gap:14px; padding:13px 0; border-top:1px solid var(--line); align-items:baseline}
.whatrow .k{font-family:var(--f-mono); font-weight:500; font-size:11px; letter-spacing:.06em; color:var(--text-muted); text-transform:uppercase}
.whatrow .v{font-size:14.5px; color:var(--text-soft); line-height:1.5}
.whatrow .v b{color:var(--text); font-weight:600}
.payoff{display:inline-flex; align-items:center; gap:9px; margin-top:20px; font-family:var(--f-display); font-weight:600; font-size:14px; color:var(--accent-lift)}
.payoff svg{width:15px; height:15px; flex:0 0 auto}

.yourbiz{margin-top:26px; background:var(--surface); border:1px solid var(--line); border-radius:var(--r-card); box-shadow:var(--sh-1); overflow:hidden}
.yb-row{display:grid; grid-template-columns:120px 1fr; gap:14px; padding:14px 18px; border-bottom:1px solid var(--line); align-items:baseline}
.yb-row:last-child{border-bottom:0}
.yb-row .k{font-family:var(--f-mono); font-weight:500; font-size:11px; letter-spacing:.06em; color:var(--text-muted); text-transform:uppercase}
.yb-row .v{font-size:14.5px; color:var(--text-soft); line-height:1.5}
.yb-row .v b{color:var(--text); font-weight:600}

/* ── the tracked-time surfaces (the running strip, and the sheet Finish opens) ──
   The strip's signature is the two-segment bar: pale travel, solid on-site
   (docs/contracts.md#time-tracking S4). A run with no travel leg draws the on-site
   segment alone, which is what the device shows. The Finish sheet has no bar — it
   asks about the two figures one at a time, and each is a field. ── */
.tsbar{display:flex; height:6px; border-radius:var(--r-round); overflow:hidden; background:var(--ap-highest)}
.tsbar i{display:block; height:100%}
.tsbar .tv{background:var(--ap-accent-c)}
.tsbar .os{background:var(--ap-accent)}
/* The strip that rides above the tab bar while a clock runs. It is LIGHT — the app draws it on the
   same raised grey as a segmented control, not on a dark bar. Once he is on site the only two
   things left to say are Pause and Finish: Send ETA and Running late are what you tap on the
   DRIVE, and he has arrived. They sit right-aligned, as the app's action rows do. */
.ap-dock{background:var(--ap-high); color:var(--ap-ink); padding:10px 12px 12px;
  border-top:1px solid var(--ap-line); display:flex; flex-direction:column; gap:8px}
.ap-dock-top{display:flex; align-items:center; gap:7px}
.ap-dock .dot{width:7px; height:7px; border-radius:50%; background:var(--ap-accent); flex:0 0 auto}
.ap-dock .ph{font:600 11.5px/16px var(--f-app)}
.ap-dock .wh{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font:400 11.5px/16px var(--f-app); color:var(--ap-ink-2)}
.ap-dock .el{margin-left:auto; font:600 14px/18px var(--f-app); font-variant-numeric:tabular-nums}
.ap-dock .tsbar{height:3px; background:var(--ap-highest)}
.ap-dock .tv{background:var(--ap-accent-c)}
.ap-dock .os{background:var(--ap-accent)}
.ap-dock-acts{display:flex; justify-content:flex-end; gap:7px}
.ap-dock-acts .ap-btn{min-height:32px; font-size:12.5px}
.ap-dock .ap-btn.tonal{background:var(--ap-highest); color:var(--ap-accent-ink)}
.ap-dock-fin{min-height:32px; padding:0 22px; font-size:12.5px;
  background:var(--ap-accent); color:#fff; border-radius:8px; display:inline-flex;
  align-items:center; font-weight:600}
/* A LIVE CALL is the same strip with a red dot on it — the app answers and mirrors the call on the
   ordinary dock rather than painting the bar red (mobile/phone/CallStrip.tsx). Its two doors are
   equal and full width, because either one is the whole point of the bar. */
.ap-dock.call{position:relative}
.ap-dock.call .dot{background:var(--ap-red)}
.ap-dock.call .ap-dock-acts .ap-btn{flex:1 1 0; min-height:36px}
/* The floating action is over the list, and this bar is over the same bottom corner. Anchoring it
   to the bar clears it whatever the bar's own height turns out to be. */
.ap-dock.call .ap-fab{bottom:100%; margin-bottom:10px}

/* ── Contacts, the keypad and a call on the work number (the /jobs work-number chapter) ──
   Contacts is a panel over the tab he was on (mobile/contacts/Contacts.tsx): the manolo number
   first, then the book. A call that rings shows in two places at once — the phone's own
   notification across the top, which Android draws in its call style with the name the app
   gives it (mobile/phone/twilio.ts), and the app's strip across the foot. The notification is
   laid over the top bar in one grid cell, so what it covers is covered and the list carries on
   from where it ends. */
.ap-under{display:grid}
.ap-under > *{grid-area:1/1; align-self:start}
.ap-under .noti{position:relative; z-index:2; flex-wrap:wrap; gap:7px 10px; margin:2px 7px; padding:9px 10px;
  background:var(--ap-card); box-shadow:0 4px 14px rgba(0,0,0,.2)}
.noti-acts{flex:1 1 100%; display:flex; gap:8px}
.os-btn{flex:1 1 0; display:inline-flex; align-items:center; justify-content:center; gap:5px; min-height:26px;
  border-radius:var(--r-round); color:#fff; font:500 11px/1 var(--f-app)}
.os-btn svg{width:13px; height:13px}
.os-btn.decline{background:var(--os-decline)}
.os-btn.decline svg{transform:rotate(135deg)}
.os-btn.answer{background:var(--os-answer)}
/* the number he gives out: the primary card, its label, the figure and Share */
.ap-numberstrip{display:flex; flex-direction:column; gap:2px; padding:8px 8px 6px 12px; border-radius:var(--ap-r);
  background:var(--ap-accent-c); color:var(--ap-accent-ink)}
.ap-numberstrip .lab{font:500 9.5px/13px var(--f-app); letter-spacing:.04em}
.ap-numberstrip .fig{display:flex; align-items:center; justify-content:space-between; gap:8px}
.ap-numberstrip b{font:400 17px/22px var(--f-app); font-variant-numeric:tabular-nums}
.ap-numberstrip .ap-btn{min-height:26px; padding:0 8px}
/* the book is ONE card with a hairline between people, the monogram where other lists put a
   docket, and the newest job chipped at the end of the row */
.ap-book{background:var(--ap-card); border-radius:var(--ap-r); overflow:hidden}
.ap-contact{display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:center; gap:10px;
  padding:7px 11px}
.ap-contact + .ap-contact{box-shadow:inset 0 1px 0 var(--ap-line)}
.ap-contact .ap-chip{margin-top:0}
/* The keypad is a sheet over Contacts (mobile/phone/Keypad.tsx): the typed number, the twelve keys
   and Call, the app's 72px keys drawn at 46 on this screen. Behind it the screen dims. */
/* a zero basis in px, not `flex:1`'s 0%: a percentage basis in a screen of no fixed height is read
   as the content's, and the screen behind would grow the phone instead of filling what is left */
.ap-behind{position:relative; flex:1 1 0px; min-height:0; overflow:hidden}
.ap-behind::after{content:""; position:absolute; inset:0; background:rgba(0,0,0,.32)}
.ap-sheet{display:flex; flex-direction:column; align-items:center; gap:10px; padding:7px 17px 14px;
  border-radius:18px 18px 0 0; background:var(--ap-card)}
.ap-grabber{width:26px; height:3px; border-radius:var(--r-round); background:var(--ap-line)}
.ap-typed{min-height:22px; font:400 17px/22px var(--f-app); font-variant-numeric:tabular-nums}
.ap-pad{display:grid; grid-template-columns:repeat(3,46px); gap:7px}
.ap-pad span{width:46px; height:46px; border-radius:50%; background:var(--ap-high); display:grid;
  place-items:center; font:400 16px/1 var(--f-app)}
.ap-callkey{width:46px; height:36px; border-radius:10px; background:var(--ap-accent); color:#fff;
  display:grid; place-items:center}
.ap-callkey svg{width:17px; height:17px}
/* the Done sheet, lifted out of the app's bottom sheet and set as a panel beside the copy. The two
   times are FIELDS because the app's are: they open on what the clock measured and he can retype
   either before saving, and nothing reaches the job until Save. */
.readback{background:var(--ap-card); border:1px solid var(--ap-line); border-radius:14px; box-shadow:var(--sh-1);
  padding:16px 18px; margin:26px 0 8px; font-family:var(--f-app); color:var(--ap-ink)}
.rb-head{font:600 15px/20px var(--f-app); margin-bottom:13px}
.rb-card{background:var(--ap-bg); border-radius:var(--ap-r); padding:12px 13px}
.rb-times{display:flex; gap:12px}
.rb-field{flex:1 1 0; min-width:0; display:flex; flex-direction:column; gap:5px}
.rb-field i{font-style:normal; font:400 11.5px/16px var(--f-app); color:var(--ap-ink-2)}
.rb-field .fld{padding:8px 10px; border:1px solid var(--ap-line); border-radius:8px;
  background:var(--ap-card); font:400 13px/18px var(--f-app)}
/* what Save will put on the job, and the edit between the measured figure above it and the money —
   the app states the round-up where it applies it (docs/contracts.md#time-tracking M2) */
.rb-sum{display:flex; align-items:baseline; gap:12px; margin-top:12px; padding-top:12px;
  border-top:1px solid var(--ap-line)}
.rb-sum-what{flex:1; min-width:0}
.rb-sum-what b{display:block; font:600 13px/18px var(--f-app)}
.rb-sum-what i{display:block; margin-top:2px; font-style:normal; font:400 11.5px/16px var(--f-app);
  color:var(--ap-ink-2)}
.rb-sum-amt{font:600 15px/20px var(--f-app); white-space:nowrap}
/* the way out, the way back and the commit, in the app's own order: destructive furthest from the
   thumb heading for Save */
.rb-acts{display:flex; justify-content:flex-end; flex-wrap:wrap; gap:8px; margin-top:14px}
.rb-acts .ap-btn{min-height:34px; font-size:12.5px}
.rb-cap{text-align:left; margin:0 0 20px}

/* The clock chapter's three pictures follow its three taps, in the two picture columns of a trio
   (above): the drive in the first, the strip and the sheet in the second. Not one of them is a
   whole screen: each is the part of the app that tap opens, so the three read as three moments
   rather than as a phone beside two panels. The strip and the sheet stack one above the other so
   they are met in order at every width — side by side, the short strip left a hole beside the tall
   sheet. Each carries the tap it follows, numbered as the scene line names them. The cap is the
   widest a column gets: below 900px there is no column, and an uncapped strip ran the full width
   of a tablet. */
.cutouts{display:grid; gap:18px; width:300px; max-width:100%; margin-inline:auto}
.cutouts .readback{margin:0}
.step{font-family:var(--f-mono); font-weight:500; font-size:11px; letter-spacing:.06em;
  color:var(--text-muted); text-transform:uppercase; margin:0 0 9px}
.stripcut{border:1px solid var(--ap-line); border-radius:14px; overflow:hidden; box-shadow:var(--sh-1);
  font-family:var(--f-app)}
.stripcut .ap-dock{border-top:0}
/* the drive has three doors where on site has two, in a strip drawn narrower than a real phone */
.ap-dock.drive .ap-btn, .ap-dock.drive .ap-dock-fin{padding:0 11px}

/* 1 · Start travel — the tap, what manolo worked out, and the text that went. Three surfaces of
   the app on the app's own ground, in the order they happen: the strip while he drives, the sheet
   Send ETA opens, and the message on the job once he taps Send text. It is drawn as a chain
   because the chain is the point — nothing is sent until he sends it (mobile/shell/TimerSheets.tsx
   EtaSheet). */
.travelcut{display:flex; flex-direction:column; gap:9px; padding-bottom:12px; background:var(--ap-bg);
  border:1px solid var(--ap-line); border-radius:14px; overflow:hidden; box-shadow:var(--sh-1);
  font-family:var(--f-app); color:var(--ap-ink)}
.travelcut .ap-dock{border-top:0}
.travelcut .then{display:grid; place-items:center; color:var(--ap-ink-2)}
.travelcut .then svg{width:14px; height:14px}
.travelcut .readback{margin:0 11px; padding:12px 13px; box-shadow:none}
.travelcut .rb-head{margin-bottom:10px}
/* the figure IS the sheet here, so the app sets it a size larger than the stepper in a row of
   other content, and centres the dial under the title */
.ap-step.big{justify-content:center; gap:14px; margin-top:0}
.ap-step.big .val{flex:0 0 auto; font-size:17px}
.travelcut .source{margin:8px 0 0; font:400 10.5px/14px var(--f-app); color:var(--ap-ink-2); text-align:center}
/* the draft is a FIELD, and that is the product rule rather than a nicety: he reads what manolo
   wrote, changes it if it isn't right, and sends it */
.travelcut .draft{margin:10px 0 0; padding:9px 10px; border:1px solid var(--ap-line); border-radius:8px;
  background:var(--ap-bg); font:400 12px/17px var(--f-app)}
.travelcut .ap-msg{margin:0 11px}

/* the photographed docket the bill was drafted from — the thread attachment above the card.
   Cropped: only its lower half shows, so it reads as the photo you took at the counter. It keeps
   the mono face because it is a printed receipt, not a screen the app drew. */
.ap-docketshot{background:var(--ap-highest); border-radius:var(--ap-r); padding:11px 11px 0; overflow:hidden;
  max-height:150px; position:relative; flex:0 0 auto}
.ap-docketshot::after{content:""; position:absolute; inset:auto 0 0 0; height:32px;
  background:linear-gradient(to bottom, rgba(227,227,232,0), rgba(227,227,232,.96))}
.ap-docketshot-paper{background:#fdfdfb; border-radius:3px; padding:10px 12px 15px; transform:rotate(-1.1deg);
  box-shadow:0 2px 8px rgba(0,0,0,.16); font-family:var(--f-mono); font-size:9px; line-height:1.7; color:#2b2f2b}
.ap-docketshot-paper .hd{display:flex; justify-content:space-between; font-weight:600; letter-spacing:.04em;
  border-bottom:1px dashed #c9c7c0; padding-bottom:5px; margin-bottom:6px}
.ap-docketshot-paper .ln{display:flex; justify-content:space-between}
.ap-docketshot-paper .tt{display:flex; justify-content:space-between; font-weight:600; border-top:1px dashed #c9c7c0;
  margin-top:5px; padding-top:5px}

/* ── the crop: one real control, lifted out of the phone and set beside the copy ──────
   The way this sheet already sets the Finish read-back sheet. It carries the app's own palette
   because what is on it IS the app, but it is not a device: there is no bezel, no status bar and
   no tab bar, because the reader is being shown one control rather than a screen. ── */
figure.phone-col{margin:0}
/* the caption heads its picture, so a row of them lines up and the pictures hang off it */
.phone-col figcaption{order:-1; margin:0 0 13px; font-size:12.5px; line-height:1.4;
  color:var(--text-muted); text-align:center; max-width:32ch}
.crop{
  --ap-bg:#f2f2f5; --ap-card:#ffffff; --ap-high:#e7e7ea; --ap-highest:#dcdce0;
  --ap-ink:#1c1c1e; --ap-ink-2:#68686e; --ap-line:#d6d6db;
  --ap-accent:#a8631a; --ap-accent-c:#f8e6cd; --ap-accent-ink:#7a4407;
  /* the flag stays clearly redder than the accent, or "needs a look" and "do this"
     become the same colour and the board stops saying anything */
  --ap-flag:#a33a12; --ap-flag-c:#f9dfd4; --ap-flag-ink:#6d2408;
  --ap-red:#d70015; --ap-neutral-c:#e3e5e8; --ap-neutral-ink:#33363a;
  --ap-mint:#e0b98a;
  --ap-outline:#a5a5aa;
  --ap-answer:#1f7a3d; --os-answer:#1e8e3e; --os-decline:#d93025;
  --ap-r:12px; --ap-r-s:6px;
  --f-app:-apple-system,'SF Pro Text','Segoe UI',Roboto,system-ui,sans-serif;
  width:300px; max-width:100%; background:var(--ap-card); border:1px solid var(--ap-line);
  border-radius:16px; box-shadow:var(--sh-2); padding:14px; font-family:var(--f-app);
  color:var(--ap-ink); display:flex; flex-direction:column; gap:10px}
.crop .ap-editor, .crop .ap-list{margin:0}
/* two buttons on a card narrower than the phone they came off: let them wrap rather than
   letting the second one hang off the edge */
.crop .ap-bill-acts{flex-wrap:wrap}

/* the reminder manolo raises when it is time to leave, as the phone draws it */
.noti{display:flex; gap:10px; align-items:flex-start; background:var(--ap-high); border-radius:14px; padding:11px 12px}
.noti-app{flex:0 0 auto; width:26px; height:26px; border-radius:7px; overflow:hidden}
.noti-app svg{display:block; width:100%; height:100%}
.noti-body{min-width:0}
.noti-top{margin:0; display:flex; gap:6px; align-items:baseline;
  font:600 11px/15px var(--f-app); color:var(--ap-ink)}
.noti-top span{font-weight:400; color:var(--ap-ink-2)}
.noti-head{margin:3px 0 0; font:600 13px/17px var(--f-app)}
.noti-text{margin:2px 0 0; font:400 11px/15px var(--f-app); color:var(--ap-ink-2)}
.noti-under{border-top:1px solid var(--ap-line); padding-top:10px;
  display:flex; flex-direction:column; gap:9px}
.noti-under .ap-booking{background:var(--ap-bg)}
.noti-under .ap-btn{align-self:stretch}

/* the quote: its header, its totals, the template note and the two controls */
.qt-head b{display:block; font:600 14px/19px var(--f-app)}
.qt-head span{display:block; margin-top:2px; font:400 11px/15px var(--f-app); color:var(--ap-ink-2)}
.ap-seg.three span{font-size:10px}
.qt-tot{display:flex; flex-direction:column; gap:5px; padding-top:9px; border-top:1px solid var(--ap-line)}
.qt-tot span{display:flex; align-items:baseline; justify-content:space-between; gap:12px}
.qt-tot i{font-style:normal; font:400 11px/15px var(--f-app); color:var(--ap-ink-2)}
.qt-tot b{font:500 12px/16px var(--f-app); font-variant-numeric:tabular-nums}
.qt-tot .big i{font-weight:600; color:var(--ap-ink)}
.qt-tot .big b{font:700 15px/20px var(--f-app)}
.qt-note{margin:0; font:400 10.5px/15px var(--f-app); color:var(--ap-ink-2)}
.qt-note b{color:var(--ap-ink); font-weight:600}
.qt-acts{display:flex; gap:8px; justify-content:flex-end}

/* the customer's page: a browser, not a phone — it is the one surface that is not the app. It
   opens on who is quoting (`backend/app/quote_page.py`): the business, its ABN, its licence and
   its address, then the quote's number, date and how long it stands, then who it is for. */
.web{border:1px solid var(--ap-line); border-radius:12px; overflow:hidden; background:var(--ap-card)}
.web-bar{background:var(--ap-high); padding:7px 10px; border-bottom:1px solid var(--ap-line)}
.web-url{display:block; background:var(--ap-card); border-radius:var(--r-round); padding:3px 10px;
  font:400 9.5px/14px var(--f-mono); color:var(--ap-ink-2)}
.web-page{padding:13px; display:flex; flex-direction:column; gap:9px}
.web-biz{margin:0; font:500 9.5px/13px var(--f-app); letter-spacing:.03em; color:var(--ap-ink-2)}
.web-id{margin:-6px 0 0; font:400 9px/13px var(--f-app); color:var(--ap-ink-2)}
.web-h{margin:0; font:700 16px/21px var(--f-app)}
.web-sub{margin:-5px 0 0; font:400 11px/15px var(--f-app); color:var(--ap-ink-2)}
.web-for{margin:-5px 0 0; font:500 11px/15px var(--f-app)}
.web-lines{display:flex; flex-direction:column; gap:7px; padding:10px 0;
  border-top:1px solid var(--ap-line); border-bottom:1px solid var(--ap-line)}
.web-lines span{display:flex; align-items:baseline; justify-content:space-between; gap:12px}
.web-lines i{font-style:normal; font:400 11.5px/16px var(--f-app)}
.web-lines b{font:500 12px/16px var(--f-app); font-variant-numeric:tabular-nums}
.web-tot{display:flex; flex-direction:column; gap:5px}
.web-tot span{display:flex; align-items:baseline; justify-content:space-between; gap:12px}
.web-tot i{font-style:normal; font:400 11px/15px var(--f-app); color:var(--ap-ink-2)}
.web-tot b{font:500 12px/16px var(--f-app); font-variant-numeric:tabular-nums}
.web-tot .big i{font-weight:600; color:var(--ap-ink)}
.web-tot .big b{font:700 15px/20px var(--f-app)}
.web-terms{margin:0; display:flex; align-items:center; gap:6px; font:400 11px/15px var(--f-app); color:var(--ap-accent)}
.web-terms svg{width:12px; height:12px; flex:0 0 auto}
.web-accept{display:flex; flex-direction:column; gap:9px; padding-top:10px; border-top:1px solid var(--ap-line)}
.web-field{display:flex; flex-direction:column; gap:4px}
.web-field i{font-style:normal; font:400 10.5px/15px var(--f-app); color:var(--ap-ink-2)}
.web-field .fld{padding:7px 9px; border:1px solid var(--ap-line); border-radius:8px; font:400 12px/17px var(--f-app)}
.web-check{display:flex; align-items:center; gap:7px; font:400 11.5px/16px var(--f-app)}
.web-check b{width:15px; height:15px; border-radius:4px; background:var(--ap-accent); color:#fff;
  display:grid; place-items:center; font-size:10px}
.web-btns{display:flex; gap:8px; justify-content:flex-end}

/* ── the bill review card (a receipt drafted into a supplier bill) ── */
.ap-bill{background:var(--ap-card); border-radius:var(--ap-r); padding:11px 12px}
.ap-bill-top{display:flex; align-items:baseline; gap:8px}
.ap-bill-top .sup{font:600 13.5px/18px var(--f-app)}
.ap-bill-top .date{margin-left:auto; font:400 10.5px/14px var(--f-app); color:var(--ap-ink-2)}
.ap-bill-chips{display:flex; gap:5px; flex-wrap:wrap; margin-top:8px}
.ap-bill-chips span{padding:2px 7px; border-radius:var(--r-round); border:1px solid var(--ap-line);
  color:var(--ap-ink-2); font:500 9px/14px var(--f-app)}
.ap-bill-line{display:flex; align-items:baseline; gap:8px; padding:8px 0; box-shadow:inset 0 -1px 0 var(--ap-line);
  font:400 11.5px/16px var(--f-app)}
.ap-bill-line:first-of-type{margin-top:5px}
.ap-bill-line .nm{min-width:0; font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ap-bill-line .gst{margin-left:auto; font:500 8.5px/14px var(--f-app); letter-spacing:.05em; color:var(--ap-ink-2)}
.ap-bill-line .amt{font-weight:500; white-space:nowrap}
.ap-bill-tot{display:flex; align-items:baseline; gap:8px; margin:0; padding-top:9px;
  font:400 10.5px/14px var(--f-app); color:var(--ap-ink-2)}
.ap-bill-tot b{margin-left:auto; font:600 13px/17px var(--f-app); color:var(--ap-ink); white-space:nowrap}
.ap-bill-row{display:flex; align-items:center; gap:8px; margin-top:10px; padding-top:10px;
  border-top:1px solid var(--ap-line); font:400 11px/16px var(--f-app); color:var(--ap-ink-2)}
.ap-bill-row + .ap-bill-row{margin-top:8px; padding-top:0; border-top:0}
.ap-bill-row .k.dark{color:var(--ap-ink)}
.ap-bill-row .v{margin-left:auto; color:var(--ap-ink); font-weight:500}
.ap-bill-ask{margin:11px 0 0; padding-top:11px; border-top:1px solid var(--ap-line);
  font:600 11.5px/16px var(--f-app); color:var(--ap-ink)}
.ap-bill-pick{display:flex; align-items:center; gap:8px; margin-top:8px; font:400 11.5px/16px var(--f-app)}
.ap-bill-pick .amt{margin-left:auto; font-weight:500; white-space:nowrap}
.tick{width:14px; height:14px; border-radius:4px; background:var(--ap-accent); color:#fff;
  display:grid; place-items:center; flex:0 0 auto}
.tick svg{width:9px; height:9px}
.ap-bill-acts{display:flex; gap:8px; margin-top:12px}
.ap-bill-acts .ap-btn:first-child{flex:1}
.ap-bill-dismiss{margin:9px 0 0; text-align:right; font:500 11px/16px var(--f-app); color:var(--ap-ink-2)}

/* ── pricing: one plan, so there is nothing to compare and no table to do it in.
   The price is a card that stays with you down the list of what is in it. ── */
.plan{display:grid; grid-template-columns:minmax(0,330px) minmax(0,1fr); gap:clamp(24px,4vw,52px); align-items:start}
.plan-card{position:sticky; top:88px; background:var(--surface); border:1px solid var(--line); border-radius:20px;
  box-shadow:var(--sh-2); padding:clamp(22px,3vw,30px); overflow:hidden}
.plan-card::before{content:""; position:absolute; inset:0 0 auto 0; height:4px; background:var(--accent)}
.plan-name{font-family:var(--f-display); font-weight:800; font-size:21px; letter-spacing:-.02em}
.plan-price{font-family:var(--f-display); font-weight:800; font-size:clamp(2.6rem,2.1rem+1.6vw,3.2rem);
  letter-spacing:-.035em; line-height:1; margin-top:12px}
.plan-price span{margin-left:4px; font-family:var(--f-body); font-weight:500; font-size:15px; letter-spacing:0; color:var(--text-muted)}
.plan-gst{margin-top:10px; font-size:14px; color:var(--text-soft)}
.plan-free{margin-top:16px; padding:12px 14px; border-radius:var(--r-sm); background:var(--accent-tint);
  border:1px solid var(--accent-line); font-size:14px; line-height:1.5; color:var(--text)}
.plan-free b{font-family:var(--f-display); font-weight:700; color:var(--accent-lift)}
.plan-card .btn{margin-top:18px; width:100%; justify-content:center}
.plan-fine{margin-top:16px; font-size:12.5px; line-height:1.55; color:var(--text-muted)}

/* what is in it: named, then said plainly. Everything is included, so there is no column of ticks */
.inc-group + .inc-group{margin-top:30px}
.inc-group h3{font-family:var(--f-display); font-weight:700; font-size:13px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--text-muted)}
.inc-row{display:grid; grid-template-columns:minmax(0,13.5rem) minmax(0,1fr); gap:16px; align-items:baseline;
  padding:14px 0; border-top:1px solid var(--line)}
.inc-group h3 + .inc-row{border-top:0; padding-top:10px}
.inc-row .k{font-family:var(--f-display); font-weight:700; font-size:15px; color:var(--text)}
.inc-row .v{font-size:14px; line-height:1.55; color:var(--text-soft)}
.inc-row .v b{color:var(--text); font-weight:600}
@media (max-width:900px){
  .plan{grid-template-columns:1fr; gap:32px}
  .plan-card{position:static}
}
@media (max-width:560px){
  .inc-row{grid-template-columns:1fr; gap:4px}
}

/* Job steps are an ordered list with visible numbers. Each step links to its
   tab page and includes one mockup row; the rail connects steps on wide screens. */
.tabs h2{font-size:clamp(1.7rem,1.3rem+1.6vw,2.4rem); font-weight:700; max-width:32ch}
.tabs .body{font-size:1.06rem; color:var(--text-soft); max-width:54ch; margin-top:16px}
.steps{list-style:none; margin:34px 0 0; padding:0; display:grid;
  grid-template-columns:repeat(4,1fr); grid-auto-rows:1fr; gap:clamp(18px,2.4vw,30px)}
.step-card{display:flex; min-width:0; container-type:inline-size}
.step-link{flex:1; min-width:0; display:flex; flex-direction:column; align-items:flex-start; gap:12px;
  text-decoration:none}
.step-top{display:flex; align-items:center; gap:10px; width:100%}
.step-n{flex:0 0 auto; width:27px; height:27px; border-radius:var(--r-round); background:var(--accent);
  color:var(--on-accent); font-family:var(--f-display); font-weight:700; font-size:13.5px;
  display:grid; place-items:center; font-variant-numeric:tabular-nums}
.step-ic{flex:0 0 auto; width:34px; height:34px; border-radius:var(--r-sm); background:var(--accent-tint);
  border:1px solid var(--accent-line); display:grid; place-items:center; color:var(--accent-lift)}
.step-ic svg{width:18px; height:18px}
.step-rail{flex:1; height:1px; min-width:8px; background:var(--line)}
.step-card h3{font-family:var(--f-display); font-weight:600; font-size:17.5px; letter-spacing:-.01em}
/* The row is drawn the width of the phone it came off, like every picture on the site. A column
   narrower than that shows its left part, and the row fades out where the column cuts it (the
   owner: "It can be cutoff at the right"). The cut is made here and not on the link, whose focus
   ring has to draw outside it.
   THE FOUR PICTURES ARE ONE HEIGHT, the tallest row's, in four columns, two and one (the owner,
   23 September 2026). `1fr` rows make every step as tall as the tallest wherever the steps wrap,
   and each title is one line at every width, so the shot below it is the same height in all four.
   The white card grows to fill it; the row inside keeps its own size, centred, because it is a
   picture of the app. */
.step-shot{align-self:stretch; flex:1 0 auto; display:flex; overflow:hidden}
.step-row{flex:none; width:300px; max-width:none; padding:8px; box-shadow:none; justify-content:center}
@container (width < 300px){
  .step-shot{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent);
    mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent)}
}
@media (hover:hover) and (pointer:fine){ .step-link:hover h3{color:var(--accent-lift)} }
@media (max-width:900px){ .steps{grid-template-columns:repeat(2,1fr); gap:28px} }
@media (max-width:560px){ .steps{grid-template-columns:1fr; gap:26px} }

/* ── a band: the copy across the top, its pictures in a row beneath ──────────────────
   A chapter draws one picture beside its words. A band draws THREE, because what it is about is
   the difference between them — three states of one control, or the three surfaces one document
   passes through — and a difference nobody can see side by side is not a picture of anything. ── */
.band .wrap{display:flex; flex-direction:column; gap:26px}
.band-copy{max-width:62ch}
.band h2{font-size:clamp(1.6rem,1.25rem+1.5vw,2.3rem); font-weight:700; margin:0; max-width:30ch}
/* a band that opens a page wears the same 1.5rem its sister pages' opening chapters wear */
.band h1{font-size:1.5rem; font-weight:700; margin:0; max-width:26ch}
.band .scene{font-size:1.06rem; color:var(--text-soft); max-width:60ch; margin-top:16px}
.band .scene b{color:var(--text); font-weight:600}
.panels{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:22px; align-items:start}
.panels .phone, .panels .crop{width:300px; max-width:100%}
.panels figcaption{margin:0 0 14px}
@media (max-width:900px){ .panels{grid-template-columns:1fr; justify-items:center} }

/* ── start CTA ── */
.start{padding-block:clamp(44px,6vw,72px)}
.start .card{background:var(--surface); border:1px solid var(--line); border-radius:20px; box-shadow:var(--sh-2); padding:clamp(28px,5vw,52px); max-width:720px; margin-inline:auto; text-align:center; position:relative; overflow:hidden}
.start .card::before{content:""; position:absolute; inset:0 0 auto 0; height:4px; background:var(--accent)}
.start h2{font-size:clamp(1.8rem,1.4rem+1.8vw,2.6rem); font-weight:800; letter-spacing:-.03em}
.start .body{font-size:1.08rem; color:var(--text-soft); max-width:46ch; margin:14px auto 0}
.start .body b{color:var(--text); font-weight:600}
/* the closing card's onward links: text, never a rival button */
.morelinks{display:flex; gap:22px; justify-content:center; flex-wrap:wrap; margin-top:18px}
.morelinks a{font-family:var(--f-display); font-weight:600; font-size:14.5px; color:var(--accent-lift);
  text-decoration:underline; text-underline-offset:3px; min-height:44px; display:inline-flex; align-items:center}
@media (hover:hover) and (pointer:fine){ .morelinks a:hover{color:var(--accent)} }
.start .btn{margin-top:26px}
.start .after{margin-top:18px; font-size:13.5px; color:var(--text-muted); max-width:48ch; margin-inline:auto}

/* ── footer ── */
.foot{border-top:1px solid var(--line); padding-block:38px; background:var(--bg)}
.foot-in{display:flex; flex-wrap:wrap; gap:20px; justify-content:space-between; align-items:flex-start}
.foot .brand{font-size:18px}
.foot .tagline{font-size:13.5px; color:var(--text-muted); margin-top:10px; max-width:40ch}
.foot .disc{font-size:12.5px; color:var(--text-muted); font-family:var(--f-mono); max-width:44ch; line-height:1.5}
.foot .cr{font-size:12.5px; color:var(--text-muted); margin-top:14px}

/* ── reveal motion (budget 3: gentle, once; content visible without JS) ── */
.js .reveal{opacity:0; transform:translateY(12px); transition:opacity .6s var(--ease-out-expo), transform .6s var(--ease-out-expo)}
.js .reveal.in{opacity:1; transform:none}
.js .settle{opacity:0; transform:scale(.96); transition:opacity .5s var(--ease-out), transform .5s var(--ease-out); transition-delay:.35s}
.js .settle.in{opacity:1; transform:none}
.stagger > *{transition-delay:calc(var(--i,0) * 90ms)}

/* ── responsive ── */
@media (max-width:900px){
  .hero-grid{grid-template-columns:1fr; gap:34px}
  .chapter .ch-grid, .chapter.flip .ch-grid, .chapter.trio .ch-grid,
  .chapter.trio:not(.flip) .ch-grid{grid-template-columns:1fr; gap:30px}
  .chapter:not(.flip) .phone-col, .chapter:not(.flip) .ch-copy{order:0}
}
@media (max-width:560px){
  .nav .btn span.lbltext{display:none}
  .nav .btn{padding:9px 12px}
  .hero h1{font-size:clamp(1.95rem,1.5rem+2.4vw,2.35rem)}
  .lg-row{grid-template-columns:1fr; gap:8px; padding:14px 16px}
  .lg-row .goto{justify-self:start}
  .nb{white-space:normal}
  .whatrow{grid-template-columns:1fr; gap:4px}
  .yb-row{grid-template-columns:1fr; gap:4px}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms !important; animation-iteration-count:1 !important; scroll-behavior:auto !important}
  .js .reveal{transform:none; transition:opacity .3s ease}
  .js .settle{transform:none; transition:opacity .3s ease; transition-delay:0s}
  .btn:active{transform:none}
}


/* ══════════════ ADDED FOR THE RE-CUT (multi-page IA) ══════════════ */

/* nav now carries the app's four tab words beside the one amber action */
.nav-nav{display:flex; align-items:center; gap:clamp(14px,2.4vw,24px); margin-left:auto;
  margin-right:clamp(14px,2.4vw,24px); padding-left:16px}  /* padding, not margin: auto collapses when the bar is full */
.nav-nav a{font-family:var(--f-display); font-weight:600; font-size:14.5px; color:var(--text-soft);
  text-decoration:none; min-height:44px; display:inline-flex; align-items:center; white-space:nowrap}
@media (hover:hover) and (pointer:fine){ .nav-nav a:hover{color:var(--text)} }
.nav-nav a[aria-current=page]{color:var(--accent-lift); box-shadow:inset 0 -2px 0 var(--accent)}
/* Keep Pricing visually separate from the four app tabs: body type and a divider. */
.nav-tabs{display:flex; align-items:center; gap:clamp(14px,2.4vw,24px)}
.nav-nav > a{font-family:var(--f-body); font-weight:500; color:var(--text-muted);
  border-left:1px solid var(--line); padding-left:clamp(14px,2.4vw,24px)}
@media (hover:hover) and (pointer:fine){ .nav-nav > a:hover{color:var(--text-soft)} }
@media (max-width:640px){
  .nav-nav{gap:12px; margin-right:12px; padding-left:12px}
  .nav-tabs{gap:12px}
  .nav-nav a{font-size:13px}
  .nav-nav > a{padding-left:12px}
}
/* Five words, a brand and a button do not fit a 390px bar at the sizes above: measured, it ran
   16px past. Everything here is width, never a dropped item — a tab word the bar hides is a tab
   the site stops naming. The 44px hit target is untouched, so a wet thumb still lands. */
@media (max-width:460px){
  .nav-nav{gap:9px; margin-right:8px; padding-left:9px}
  .nav-tabs{gap:9px}
  .nav-nav a{font-size:12.5px; letter-spacing:-.01em}
  .nav-nav > a{padding-left:9px}
}
/* Below 360px the five words cannot share a row with the brand and the button at any readable
   size — squeezed onto one line they wanted 284px of the 232px there are. So the bar takes a
   second row instead of shrinking the type: brand and action above, the four tabs and Pricing
   spread across the width below, in the same two styles. */
@media (max-width:360px){
  .nav-in{flex-wrap:wrap; height:auto; padding-top:9px; padding-bottom:5px}
  .nav-nav{order:3; width:100%; margin:0; padding-left:0; justify-content:space-between}
}
/* one name per page: the wordmark yields before a nav label ever shortens */
@media (max-width:640px){ .brand{gap:0} .brand .wordmark{display:none} }

/* the sub-pages open on a plain band of type, not a phone */
.pagehead .wrap{display:grid; grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr); gap:clamp(20px,4vw,56px); align-items:end}
.pagehead h1,.pagehead h2{margin-top:0; font-weight:800; font-size:clamp(1.95rem,1.35rem+2.4vw,2.9rem); letter-spacing:-.03em; margin-top:14px; max-width:19ch}
.pagehead .lede{font-size:clamp(1.05rem,1rem+.4vw,1.2rem); color:var(--text-soft); max-width:48ch; margin-top:0; padding-bottom:5px}
@media (max-width:900px){
  .pagehead .wrap{grid-template-columns:1fr; gap:14px; align-items:start}
  .pagehead .lede{padding-bottom:0}
}
.pagehead .lede b{color:var(--text); font-weight:600}

/* the Plans page's two cards are the section — its heading is the page's h1 */
.visually-hidden-head{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap}


/* ══════ split phone frames: one screen shown as two halves, torn at a wavy edge ══════
   Long screens (the drafted bill, the thread with its card, the Items list) ran twice the
   height of the copy beside them. Split, the pair reads left-to-right and the column stays
   level with the words. The wave is the join, the way a torn docket shows where it carried on. */
.chapter.pair .ch-grid{grid-template-columns:minmax(0,624px) minmax(0,1fr)}
.chapter.pair.flip .ch-grid{grid-template-columns:minmax(0,1fr) minmax(0,624px)}
.phone-pair{display:flex; gap:24px; align-items:flex-start; justify-content:center}
/* The 300 is a width and never a flex BASIS. Stacked below 700px the main axis turns vertical,
   where a basis is a HEIGHT no half may fall below — so a half with less than 300px of content
   is padded out in bezel colour, and the dark band reads as two devices instead of one. */
.phone-pair .phone{width:300px; flex:0 0 auto; margin-inline:0}
.phone-pair .phone .screen{min-height:0}
/* A floating action floats over the bottom of a full screen. Half a screen is short enough that it
   lands on the last row instead — over the Add button, in the Items pair — so in a pair it drops
   out of the float and sits above the tab bar as its own row. */
.phone-pair .ap-fab{position:static; align-self:flex-end; margin:2px 12px 10px}
/* The tear is the DEVICE's own edge, not a line drawn inside it: the phone is masked so its
   bezel, screen and shadow all stop on the same wave. A is opaque above the curve, B below the
   identical curve, so the two halves interlock like one torn docket. */
.phone.part-a, .phone.part-b{
  --wave-a:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='14' preserveAspectRatio='none'%3E%3Cpath d='M0 0 H60 V7 q-7.5 -6 -15 0 t-15 0 t-15 0 t-15 0 Z' fill='%23000'/%3E%3C/svg%3E");
  --wave-b:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='14' preserveAspectRatio='none'%3E%3Cpath d='M0 14 V7 q7.5 -6 15 0 t15 0 t15 0 t15 0 V14 Z' fill='%23000'/%3E%3C/svg%3E");
  --solid:linear-gradient(#000,#000);
}
.phone.part-a{
  border-bottom-left-radius:0; border-bottom-right-radius:0; padding-bottom:0;
  -webkit-mask-image:var(--wave-a), var(--solid);  mask-image:var(--wave-a), var(--solid);
  -webkit-mask-size:60px 14px, 100% calc(100% - 13px);  mask-size:60px 14px, 100% calc(100% - 13px);
  -webkit-mask-position:left bottom, left top;  mask-position:left bottom, left top;
  -webkit-mask-repeat:repeat-x, no-repeat;  mask-repeat:repeat-x, no-repeat;
}
.phone.part-b{
  border-top-left-radius:0; border-top-right-radius:0; padding-top:0;
  -webkit-mask-image:var(--wave-b), var(--solid);  mask-image:var(--wave-b), var(--solid);
  -webkit-mask-size:60px 14px, 100% calc(100% - 13px);  mask-size:60px 14px, 100% calc(100% - 13px);
  -webkit-mask-position:left top, left bottom;  mask-position:left top, left bottom;
  -webkit-mask-repeat:repeat-x, no-repeat;  mask-repeat:repeat-x, no-repeat;
}
/* the screen must square off where the device is torn, or its radius shows through the tear */
.phone.part-a .screen{border-bottom-left-radius:0; border-bottom-right-radius:0}
/* B's `padding-top:0` above is the device edge landing on the tear and must stay, or the mask
   stops lining up — so the clearance for whatever the bottom half opens on goes on the SCREEN.
   The wave is 14px with its trough ~7px down, so 10px clears the deepest point. */
.phone.part-b .screen{border-top-left-radius:0; border-top-right-radius:0; padding-top:10px}

@media (max-width:1040px){
  .chapter.pair .ch-grid, .chapter.pair.flip .ch-grid{grid-template-columns:1fr}
  /* stacked here, so the words go back on top: the phone-first `order` is for two columns only */
  .chapter.pair .phone-col, .chapter.pair .ch-copy{order:0}
}
/* Narrow enough and the two halves rejoin into ONE tall device: the tear is undone, the
   bezel runs straight through, and the screen reads as the single scroll it always was.
   Splitting only ever existed to keep the frame level with the copy beside it, and there is
   no copy beside it here. */
@media (max-width:700px){
  .phone-pair{flex-direction:column; align-items:center; gap:0}
  .phone.part-a, .phone.part-b{-webkit-mask-image:none; mask-image:none}
  .phone.part-a{padding-bottom:0; border-bottom-left-radius:0; border-bottom-right-radius:0; box-shadow:none}
  .phone.part-b{padding-top:0;   border-top-left-radius:0;    border-top-right-radius:0}
  /* one shadow for one device, cast by the half that ends it. It reaches ~6px back up over A's
     bezel, though, and stops dead at the join — a step from #343a43 to #3a4049 straight across
     the rails, which is the seam again in a fainter ink. A paints over it instead. */
  .phone.part-b{box-shadow:var(--sh-2)}
  .phone.part-a{position:relative; z-index:1}
  /* the two screens' own hairlines would meet as a seam across the middle of one device */
  .phone.part-a .screen{border-bottom:0}
  /* and the clearance above B's content only existed to clear the tear, which is gone here */
  .phone.part-b .screen{border-top:0; padding-top:0}
}

/* ══════ the waitlist form (front page) ══════ */
/* an anchored section opens BELOW the sticky bar, not under it */
main > section[id]{scroll-margin-top:64px}
.signup{margin-top:26px; max-width:440px}
.field-row{display:flex; gap:10px; flex-wrap:wrap; align-items:flex-end}
.field{flex:1 1 220px; min-width:0}
.field-btn{flex:0 0 auto}
label.lbl{display:block; font-size:13.5px; font-weight:600; color:var(--text-soft); margin-bottom:6px; font-family:var(--f-body)}
input[type=email]{
  width:100%; font:inherit; font-size:16px; padding:13px 14px; border-radius:var(--r-sm);
  border:1px solid var(--line); background:var(--surface); color:var(--text); min-height:48px;
  transition:border-color .15s ease, box-shadow .15s ease;
}
input[type=email]::placeholder{color:var(--text-muted)}
input[type=email]:focus-visible{outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-tint)}
.signup .btn{min-height:48px; padding:13px 20px; flex:0 0 auto}
.hp{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden}
.formnote{margin-top:14px; font-size:12.5px; line-height:1.55; color:var(--text-muted); max-width:52ch}
.formnote b{font-weight:600; color:var(--text-soft)}
.formnote a{color:var(--text-soft)}
.formmsg{margin-top:12px; font-size:14.5px; font-weight:500; display:none}
.formmsg.err{display:block; color:var(--flag-ink)}
input.invalid{border-color:var(--flag); box-shadow:0 0 0 3px rgba(200,128,26,.14)}
.btn[aria-busy=true]{opacity:.9}
.spin{width:16px; height:16px; border-radius:50%; border:2px solid rgba(26,20,8,.35); border-top-color:var(--on-accent); display:none; animation:spin .7s linear infinite}
.btn[aria-busy=true] .spin{display:inline-block}
.btn[aria-busy=true] .ic-arrow{display:none}
@keyframes spin{to{transform:rotate(360deg)}}
.signup.done .form-live{display:none}
.signup .done-panel{display:none}
.signup.done .done-panel{display:flex; gap:12px; align-items:flex-start; padding:16px 18px; border:1px solid var(--accent);
  background:var(--accent-tint); border-radius:var(--r-card); text-align:left}
.done-panel .tick{flex:0 0 auto; width:26px; height:26px; border-radius:50%; background:var(--accent); color:var(--on-accent); display:grid; place-items:center; margin-top:1px}
.done-panel .tick svg{width:15px; height:15px}
.done-panel strong{font-family:var(--f-display); font-weight:700; font-size:16px}
.done-panel p{font-size:14px; color:var(--text-soft); margin-top:3px}
.start .signup{margin-inline:auto; margin-top:26px; text-align:left}
.start .signup .field-row{justify-content:center}

/* ══════ the store badges and their popup ══════
   manolo is in neither store, so a badge is a button that opens the popup and never a link.
   Without JavaScript nothing could open it, so without JavaScript it is not drawn. */
.badges{display:flex; gap:10px; flex-wrap:wrap; margin-top:20px}
html:not(.js) .badges{display:none}
.store-badge{display:inline-flex; flex-direction:column; align-items:flex-start; justify-content:center; gap:1px;
  min-height:48px; padding:7px 16px; border-radius:var(--r-sm); border:1px solid var(--line); background:var(--bg-sunk);
  color:var(--text); cursor:pointer; text-align:left; touch-action:manipulation;
  transition:border-color .15s ease, transform .16s var(--ease-out)}
.store-badge .sb-lead{font-family:var(--f-mono); font-size:10px; letter-spacing:.05em; text-transform:uppercase; color:var(--text-muted)}
.store-badge .sb-name{font-family:var(--f-display); font-weight:700; font-size:16px; letter-spacing:-.01em}
.store-badge:active{transform:scale(.97)}
@media (hover:hover) and (pointer:fine){ .store-badge:hover{border-color:var(--accent)} }
dialog.cs{padding:0; border:1px solid var(--line); border-radius:20px; background:var(--surface); color:var(--text);
  box-shadow:var(--sh-2); width:min(440px,calc(100vw - 32px)); max-height:calc(100dvh - 32px); overflow:auto}
dialog.cs::backdrop{background:rgba(8,9,12,.72)}
/* the padding is on the INSIDE box, so a tap on the backdrop lands on the dialog element itself */
.cs-in{position:relative; padding:clamp(26px,6vw,36px); text-align:center}
.cs-x{position:absolute; top:8px; right:8px; width:44px; height:44px; display:grid; place-items:center; border:0;
  background:transparent; color:var(--text-muted); border-radius:var(--r-sm); cursor:pointer}
.cs-x svg{width:18px; height:18px}
@media (hover:hover) and (pointer:fine){ .cs-x:hover{color:var(--text)} }
.cs-store{font-family:var(--f-mono); font-weight:500; font-size:11px; letter-spacing:.06em; text-transform:uppercase; color:var(--accent-lift); min-height:1.55em}
.cs h2{font-weight:800; font-size:clamp(1.5rem,1.3rem+1vw,1.9rem); letter-spacing:-.03em; margin-top:6px}
#cs-body{margin-top:12px; color:var(--text-soft)}
.cs .btn{margin-top:22px}

/* four links in a row are four tap targets: give each the height a thumb needs */
.foot .cr a{display:inline-block; padding-block:6px}
