:root{--accent:#F6FFEB;--accent-soft:rgba(246,255,235,0.16);--accent-dim:rgba(246,255,235,0.45);
  --space-1:8px;--space-2:16px;--space-3:24px;--space-4:40px;--space-5:64px;--space-6:100px;
  /* LOZENGE — the compact pill/tag/chip/nav-item/small-icon-button family:
     .topnav-item .os-nav-item .os-topnav-new .os-topnav-today .pill
     .files-trigger .invoice-status .tl-iconbtn .tl-chip .tl-toggle
     .dmod-status .client-pill .os-stage .dbtn .lib-addbtn .os-new-item
     .os-tool-trigger .person-nda-mark .stack-find .orient-action
     .prop-express-cta .prop-express-done
     Mobile-only (below 600px): .pan-pill .nav-collapse-trigger .nav-sheet-item
     One shared height across all of them — change here, not per-class.
     Kept out on purpose: .os-waiting/.os-paidpill/.mod-remove still carry this
     token but have no real caller left in app.js/os.js (see
     .claude/dead-css-audit.md) — don't resurrect them as "the" example of
     anything without checking a real call site still exists.
     See styleguide.html for live samples — keep both in sync. */
  --lozenge-h:25px;}
/* Every lozenge centres its label with flex align-items:center, which centres
   the LINE BOX — and with line-height left at "normal" that box comes from
   the font file's own ascent/descent/line-gap metrics, not from anything
   this app controls. The 2026-09-01 Project X refresh changed those metrics
   (unified across all 7 weights), which visibly shifted every lozenge's text
   off-centre even though nothing here changed — line-height:1 collapses the
   line box to exactly font-size, so centring no longer depends on whichever
   metrics table happens to ship in the current font build. Same selector
   list as the family comment above — keep both in sync.
   line-height:1 alone still leaves labels sitting visibly high, because this
   typeface's reserved descent (~0.22em) is real (used for hhea/OS2 layout)
   but our lozenge labels are all-caps and never render an actual descender —
   measured via canvas TextMetrics at 11px/700: fontBoundingBoxDescent 2px vs
   actualBoundingBoxDescent ~0.01px, i.e. ~2px reserved below the baseline
   that the glyphs never use, vs only ~1.2px slack above cap-height — so the
   centred LINE BOX still isn't where the visible INK sits. line-height can't
   fix this on its own (half-leading is always added symmetrically, so no
   value of it changes the ascent:descent split baked into the font); each
   affected member below instead carries its own padding-top:0.5px/
   padding-bottom:0 to pull the ink down to true centre — measured empirically
   per member (render a Range around the label's text node, compare its
   getBoundingClientRect() to the element's own), NOT derived from the canvas
   metrics above: those predicted a ~1px correction, but every member
   measured at exactly 10px font-size (.dbtn, .pill, .os-new-item) already
   centred at 0px excess, while every OTHER size (8/9/11px: .topnav-item,
   .client-pill, .dmod-status, .files-trigger, .os-tool-trigger,
   .person-nda-mark, .os-stage) measured exactly 0.5px low — a quantised
   rounding artefact of this font/size combination, not a smooth function of
   size, so re-measure before assuming the same 0.5px applies to a new size
   rather than recomputing from the canvas ascent/descent numbers directly.
   Excluded: .os-nav-item, whose label sits beside a fixed 25×25 .stack-count
   badge already flush to the full lozenge height — shrinking its content box
   would push the badge off-centre instead; fixing that one needs a markup
   change (wrap the label in its own span), not a padding tweak. Re-measure
   all of this if a future font update changes the ascent:descent ratio again
   (currently identical across all 7 weights, OS/2 typo 820:-220). */
.topnav-item,.os-nav-item,.os-topnav-new,.os-topnav-today,.pill,.files-trigger,
.invoice-status,.tl-iconbtn,.tl-chip,.tl-toggle,.dmod-status,.client-pill,
.os-stage,.dbtn,.lib-addbtn,.os-new-item,.os-tool-trigger,.person-nda-mark,
.stack-find,.orient-action,.prop-express-cta,.prop-express-done,.pan-pill,
.nav-collapse-trigger,.nav-sheet-item{line-height:1;}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
html,body{background:#F0F2EF;color:#000;font-family:"Project X",sans-serif;-webkit-font-smoothing:antialiased;}
#root{width:100%;}
.page{width:900px;max-width:100%;margin:0 auto;background:#F0F2EF;padding-bottom:150px;}
.page-delivery{display:flex;flex-direction:column;min-height:100vh;}

/* MOTION — nothing bounces, nothing exceeds 250ms except ambient loops */
.page.anim{animation:calmIn .5s cubic-bezier(.16,1,.3,1);}
@keyframes calmIn{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:none;}}
/* state switch — the new page drifts in on the house curve */
.page.state-in{animation:stateIn .22s cubic-bezier(.16,1,.3,1);}
@keyframes stateIn{from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:none;}}
/* the orientation line's one calm reveal whenever its sentence actually
   changes — a fade + a few px drift in from the left, once per change. */
.orient-line.orient-reveal{animation:orientReveal .25s ease-out;}
@keyframes orientReveal{from{opacity:0;transform:translateX(-8px);}to{opacity:1;transform:none;}}
/* the module body the user just opened reveals; others rebuilt by render stay still */
.module-body.body-enter,.tl-module-body.body-enter{animation:bodyIn .24s cubic-bezier(.16,1,.3,1);}
@keyframes bodyIn{from{opacity:0;transform:translateY(-6px);}to{opacity:1;transform:none;}}
@media (prefers-reduced-motion:reduce){
  .page.anim,.page.state-in,.orient-line.orient-reveal,.module-body.body-enter,.tl-module-body.body-enter,
  .prop-intro-box,.quote-fill,.quote-dot{animation:none!important;transition:none!important;}
}

/* Printed single documents (invoices): #print-doc replaces the app — see @media print */
#print-doc{display:none;}

/* INTRO SLIDE — page 01 of the proposal deck. Full-bleed white interactive
   gradient + generative canvas, intro sentence centred.
   .topnav sits BEFORE .page-proposal in the DOM as a normal (if sticky)
   block — at scroll 0 it reserves its own height above the deck rather than
   overlapping it, and since the nav itself has no fill, that reserved strip
   shows the bare page background: a grey bar between the nav and this
   slide's white on first open, and — since sticky means the nav keeps that
   same natural position rather than being pinned by transform — the exact
   thing that appears/disappears on any rubber-band scroll. Pulling the
   slide up by the nav's real height (synced into --topnav-h — see
   syncTopnavHeight()) makes it start at document y:0 like the nav does, so
   the two overlap instead of stack: the nav then shows this slide's own
   white through its transparent background, with nothing beneath either to
   ever reveal. Scoped to the intro only — every other slide already starts
   below the nav's reserved space, which is correct for them. */
.prop-slide-intro{position:relative;overflow:hidden;padding:0!important;margin-top:calc(-1 * var(--topnav-h, 55px));}
.gen-canvas{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;}
/* Full-width white at the top fading to the page grey by the lower third, so
   page 01 blends into page 02. */
.prop-intro-box{position:absolute;inset:0;background:linear-gradient(to bottom,#fff 0%,rgba(255,255,255,0) 68%);animation:calmPulse 6s ease-in-out infinite;pointer-events:none;}
@keyframes calmPulse{0%,100%{opacity:0.65;transform:scale(1);}50%{opacity:1;transform:scale(1.02);}}
.prop-intro-text{position:relative;z-index:1;font-family:"Project X",sans-serif;font-weight:500;font-size:1.73vmin;letter-spacing:0.2px;line-height:1.25;color:#000;text-align:center;padding:var(--slide-gap);}

/* ADMIN MODE — lives inside the sticky topnav row, same height as the tab pills */
.topnav-admin{grid-column:1;justify-self:start;display:flex;align-items:flex-start;gap:8px;}
.record-menu-wrap{position:relative;display:flex;}
/* Bar colour IS the save-state signal now — not a fixed black chrome strip.
   Standard/clean (published, nothing pending) is the same pale green the OS
   uses everywhere else for "live" (#edffd7, matches --tl-live/.os-stage-live);
   dirty (surfaceIsDirty(), computed into the class at build time in
   adminEditBar() and kept live by syncEditBar() on every inline edit) swaps
   to the OS's paired attention fill (#ffe1d7 bg / #ff7070 ink — same pair as
   .os-entry-person.is-missing). Never black again on purpose. */
.admin-bar-fixed{position:fixed;top:0;left:0;right:0;height:28px;z-index:70;display:flex;align-items:center;justify-content:space-between;padding:0 16px;background:#edffd7;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;}
.admin-bar-fixed.is-dirty{background:#ffe1d7;}
/* Scoped to .admin-bar-fixed, not the bare class — .admin-bar-label is
   reused as .box-head-label too (the floating record box's own header,
   still hardcoded black — see .box-head below), which needs to keep its
   own white regardless of what colour the actual admin bar is doing. */
.admin-bar-fixed .admin-bar-label{color:rgba(0,0,0,.65);}
.admin-bar-fixed.is-dirty .admin-bar-label{color:#ff7070;}
/* Plain project surface only — "Admin mode" sits at the bar's true visual
   centre no matter what's on either side of it (the back arrow at left; the
   Publish chip only sometimes present at right, adminEditBar, app.js).
   position:absolute against .admin-bar-fixed itself (already position:fixed,
   a valid containing block) rather than flex order/space-between, so
   centring never depends on — and never shifts with — a sibling's width. */
.admin-bar-label--centered{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);}
/* The project surface's one way back — real navigation to where the link
   sits in the OS (?os&view=projects), not the plain /?os the old (removed)
   .admin-bar-back link was. Same colour as the label beside it. */
.admin-bar-back{display:inline-flex;align-items:center;justify-content:center;color:rgba(0,0,0,.65);transition:color .15s;}
.admin-bar-back:hover{color:#000;}
.admin-bar-fixed.is-dirty .admin-bar-back{color:#ff7070;}
/* Higher specificity than the plain :hover above on purpose — hover always
   settles on black, even over the dirty state's red resting colour. */
.admin-bar-fixed.is-dirty .admin-bar-back:hover{color:#000;}
html.admin-chrome .topnav{top:28px;}
html.admin-chrome body{padding-top:28px;}
html.admin-chrome .os-new-wrap,html.admin-chrome .os-today-wrap{top:38px;}
html.admin-chrome .os-pan-pills-bar{top:calc(var(--topnav-h,46px) + 28px);}
/* Preserve the received 2px directory padding when the filter row sticks. */
.os .stack-bar{top:calc(var(--topnav-h,42px) + 2px);}
html.admin-chrome .os .stack-bar{top:calc(var(--topnav-h,42px) + 28px + 2px);}
/* The bar's own Save — hidden until surfaceIsDirty() says this surface
   actually differs from what's saved (see syncEditBar, app.js). Replaces the
   old separate bottom-of-screen "publishbar" pill: one Save, always in the
   same place, on all three admin surfaces (project/?doc=/?record=). */
.admin-bar-dirty{display:none;align-items:center;gap:10px;}
.admin-bar-dirty.show{display:flex;}
/* Solid, not dimmed — this chip only ever renders while surfaceIsDirty() is
   true (its .show gate), so it's always sitting on the dirty/pink bar; same
   full-strength red as the app's other attention text (.os-entry-person.
   is-missing), never toned down the way the label/back-arrow's resting
   colour is. */
.admin-bar-dirtymsg{color:#ff7070;}
/* Clickable only on the plain project surface (syncEditBar sets this class
   there alone) — opens the same publish-diff review the Save/Publish button
   does, without committing. admin-bar-prompts.md PROMPT 3. */
.admin-bar-dirtymsg.is-clickable{cursor:pointer;text-decoration:underline;text-decoration-color:rgba(255,112,112,.4);transition:color .15s;}
.admin-bar-dirtymsg.is-clickable:hover{color:#000;}
.admin-bar-save{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;background:#fff;color:#000;border:none;border-radius:5px;padding:6px 12px;cursor:pointer;transition:opacity .15s;}
.admin-bar-save:hover{opacity:.85;}

/* .invoice-status is still used inside the printed invoice document
   (invoiceDocHTML) — a different render path from the deleted dropdown. */
.invoice-status{display:inline-flex;align-items:center;height:var(--lozenge-h);font-family:"Project X",sans-serif;font-weight:500;font-size:8px;letter-spacing:0.5px;text-transform:uppercase;padding:0 8px;border-radius:8px;}
.invoice-status.pending{background:var(--accent-soft);color:rgba(0,0,0,0.6);}
.invoice-status.paid{background:#000;color:#fff;}

/* FILES — a persistent utility, not a competing call-to-action, so it sits at
   whisper weight (transparent, thin border) rather than full-weight black.
   Self-contained popover shell (mirrors .os-tool-pop's pattern) — does not
   depend on any invoice-menu class, which is gone entirely now. */
/* margin-right:-31px pulls Vault's right edge from the 46px topnav padding
   out to 15px, matching orient-line's top:15px so both corner elements sit
   an equal distance from their nearest edge. */
.files-trigger{display:inline-flex;align-items:center;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.35);background:transparent;border:0.5px solid rgba(0,0,0,0.15);border-radius:5px;height:var(--lozenge-h);padding:0.5px 14px 0;cursor:pointer;transition:color .2s,border-color .2s;margin-right:-31px;}
.files-trigger:hover{color:rgba(0,0,0,0.6);border-color:rgba(0,0,0,0.3);}
.files-dropdown{position:absolute;top:100%;right:0;left:auto;margin-top:8px;width:280px;background:#fff;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:16px;z-index:45;box-shadow:0 10px 34px rgba(0,0,0,0.12);}
.files-section+.files-section{margin-top:16px;padding-top:16px;border-top:0.5px solid rgba(0,0,0,0.12);}
.files-section-label{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.4);margin-bottom:12px;}
.files-row{display:flex;align-items:center;justify-content:space-between;gap:12px;}
.files-row+.files-row{padding-top:14px;border-top:0.5px solid rgba(0,0,0,0.1);}
.files-row-top{display:flex;flex-direction:column;gap:3px;min-width:0;}
.files-row-name{font-family:"Project X",sans-serif;font-weight:500;font-size:11px;color:#000;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.files-row-date{font-family:"Project X",sans-serif;font-size:9px;letter-spacing:0.3px;text-transform:uppercase;color:rgba(0,0,0,0.4);}
.files-row-actions .dbtn{font-size:9px;padding:5px 12px;margin-top:0;}

/* INVOICE DOCUMENT — captured to PDF; reuses app components but stays black/white/grey */
.invoice-doc{width:210mm;min-height:297mm;box-sizing:border-box;background:#fff;padding:22mm 18mm;font-family:"Project X",sans-serif;color:#000;display:flex;flex-direction:column;}
.invoice-doc .invoice-status.pending{background:#ececea;color:rgba(0,0,0,0.6);}

.invoice-doc-top{display:flex;align-items:flex-start;justify-content:space-between;padding-bottom:28px;border-bottom:1px solid rgba(0,0,0,0.08);margin-bottom:28px;}
.invoice-doc-brandname{font-family:"Project X",sans-serif;font-weight:600;font-size:20px;letter-spacing:0.02em;margin-bottom:8px;}
.invoice-doc-brandaddr{font-family:"Project X",sans-serif;font-size:11px;color:rgba(0,0,0,0.45);line-height:1.5;}
.invoice-doc-toptitle{text-align:right;}
.invoice-doc-titleword{font-family:"Project X",sans-serif;font-weight:200;font-size:26px;letter-spacing:0.02em;text-transform:uppercase;color:rgba(0,0,0,0.85);}
.invoice-doc-titlenum{font-family:"Project X",sans-serif;font-size:11px;color:rgba(0,0,0,0.4);margin-top:4px;letter-spacing:0.04em;}

.invoice-doc-infobar{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:36px;gap:32px;}
.invoice-doc-infogroup.right{text-align:right;}
.invoice-doc-infolabel{display:block;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.06em;text-transform:uppercase;color:rgba(0,0,0,0.35);}
.invoice-doc-inforow{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:6px;}
.invoice-doc-inforow .invoice-doc-infolabel{margin-bottom:0;}
.invoice-doc-infoval{display:block;font-family:"Project X",sans-serif;font-size:12px;color:#000;margin-top:3px;}
/* This is always the bill-to company/entity name (invoiceDocHTML's f()) —
   company names read in full caps everywhere, same rule as the OS's own
   Client rows (.os-entry-name--company). */
.invoice-doc-infoval.strong{font-weight:500;font-size:13px;margin-top:6px;text-transform:uppercase;}
.invoice-doc-infoval.muted{color:rgba(0,0,0,0.45);font-size:11px;margin-top:2px;}
.invoice-doc-inforow .invoice-doc-infoval{margin-top:0;}

.invoice-doc-table{width:100%;border-collapse:collapse;margin-bottom:32px;}
.invoice-doc-table thead th{text-align:left;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.06em;text-transform:uppercase;color:rgba(0,0,0,0.35);padding-bottom:10px;border-bottom:1px solid rgba(0,0,0,0.1);}
.invoice-doc-table thead th.num,.invoice-doc-table td.num{text-align:right;}
.invoice-doc-table tbody td{font-family:"Project X",sans-serif;font-size:13px;color:#000;padding:16px 0;border-bottom:1px solid rgba(0,0,0,0.08);}
.invoice-doc-table tfoot td{font-family:"Project X",sans-serif;font-weight:600;font-size:14px;color:#000;padding:16px 0 0;border-top:2px solid var(--accent);}

.invoice-doc-payment{margin-bottom:48px;}
.invoice-doc-paylabel{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.06em;text-transform:uppercase;color:rgba(0,0,0,0.35);margin-bottom:14px;}
.invoice-doc-paygrid{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;background:rgba(0,0,0,0.02);border-radius:8px;padding:18px 20px;}
.invoice-doc-payitem .invoice-doc-infoval{margin-top:3px;font-size:12px;}

.invoice-doc-footer{display:flex;justify-content:center;margin-top:auto;padding-top:32px;}
/* An invoice is ONE document in two modes: the client sees plain text, admin
   sees the identical layout with every value editable in place. Same affordance
   language as the proposal's own inline edit (.ae) so "this is editable" reads
   the same everywhere. Never shown once the invoice is paid/locked. */
.invoice-doc-edit{outline:none;border-radius:3px;cursor:text;display:inline-block;min-width:1ch;}
.invoice-doc-edit:hover{background:rgba(0,0,0,0.05);box-shadow:0 1px 0 0 rgba(0,0,0,0.2);}
.invoice-doc-edit:focus{background:var(--accent-soft);box-shadow:0 0 0 1.5px var(--accent);}
.invoice-doc-edit:empty:before{content:attr(data-placeholder);color:rgba(0,0,0,0.3);}
.record-doc-wrap{max-width:820px;margin:0 auto;}
.record-doc-actions{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-top:24px;}
.record-doc-wrap .os-row-meta{text-align:center;margin-top:10px;}
.ae{outline:none;border-radius:3px;cursor:text;}
.ae:hover{background:rgba(0,0,0,0.04);box-shadow:0 1px 0 0 rgba(0,0,0,0.2);}
.ae:focus{background:var(--accent-soft);box-shadow:0 0 0 1.5px var(--accent);}
.ae:empty:not(:focus){box-shadow:0 0 0 1px var(--accent-dim);background:var(--accent-soft);}
.ae:empty:not(:focus)::before{content:"Add copy";color:rgba(0,0,0,0.3);}
/* The Publish review modal (.modal-wide/.pub-diff-*) is retired — document-
   first-admin-surface-prompts.md, 2026-09-04 — the box's own Publish row
   shows the same diff inline, as a hover tip (see .tip below). */

/* TOP NAV */
.topnav{position:sticky;top:0;z-index:20;display:grid;grid-template-columns:minmax(140px,1fr) auto minmax(140px,1fr);align-items:start;padding:0 46px;}
.topnav-center{grid-column:2;justify-self:center;display:flex;flex-direction:column;align-items:center;padding:15px 0;}
.topnav-os .topnav-center{padding-bottom:0;}
.topnav-track{display:inline-flex;gap:2px;flex-wrap:wrap;justify-content:center;}
.topnav-admin{padding-top:15px;}
.topnav-right{grid-column:3;justify-self:end;display:flex;align-items:flex-start;gap:10px;padding-top:15px;}
/* margin-right:-22px pulls the date's right edge from the 46px topnav padding
   out to 24px, aligning it with the fixed page-number lozenge (right:24px). */
.topnav-date{margin-top:0;margin-right:-22px;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);}
/* Pixel-matched to Figma node 3392:8519 ("Menu - Persons", MATA_OS file) —
   radius 6px (was 5), Mata_07/700 weight (was 500), 11px/0.55px tracking
   (was 10px/0.5px). The active state used to also match that node's solid
   black pill (#0c0c0c bg, white text) — deliberately overridden below to
   the same grey as resting, solid black text instead of the black pill;
   diverges from the Figma spec on purpose, confirmed. */
.topnav-item{display:inline-flex;align-items:center;justify-content:center;padding:0.5px 15px 0;height:var(--lozenge-h);border:none;border-radius:6px;background:rgb(232,232,232);cursor:pointer;font-family:"Project X",sans-serif;font-weight:700;font-size:11px;letter-spacing:0.55px;text-transform:uppercase;color:rgba(0,0,0,0.3);transition:color .2s ease,background .2s ease;white-space:nowrap;}
.topnav-item:hover{color:rgba(0,0,0,0.55);}
.topnav-item.active{background:rgb(232,232,232);color:#000;}

/* PILLS */
.pill{display:inline-flex;align-items:center;justify-content:center;padding:0 14px;height:var(--lozenge-h);border-radius:5px;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:#000;white-space:nowrap;}
.pill-outline{background:transparent;border:0.5px solid rgba(0,0,0,0.15);}

/* HEADER */
.header{display:flex;justify-content:space-between;align-items:center;padding:20px 46px;}
.sig{display:block;opacity:.9;}

/* HERO — proposal title spec: Project X 400, 53px, 100% */
.hero{padding:50px 46px 36px;display:flex;justify-content:space-between;align-items:flex-end;}
.hero-title{font-family:"Project X",sans-serif;font-weight:200;font-size:53px;line-height:100%;letter-spacing:normal;color:#000;}
.hero-center{justify-content:center;text-align:center;padding:80px 46px 80px;}
.hero-center .hero-title{text-align:center;letter-spacing:-0.04em;}
.hero-compact{margin-top:var(--space-6);padding:var(--space-5) 46px var(--space-4);}
.hero-center .hero-title-sm{font-size:18px;font-weight:600;line-height:110%;letter-spacing:0.02em;}

/* APPROACH */
.approach{margin:var(--space-6) 46px 0;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:20px 24px 28px;}
.approach-proposal{padding:50px 20px 40px;background:#F6FFEB;border-color:transparent;}
.approach-label{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.25);margin-bottom:0;}
.approach-text{font-family:"Project X",sans-serif;font-size:38px;font-weight:200;letter-spacing:-1px;line-height:1.1;color:#000;}
.approach-text strong{font-weight:inherit;}

/* CHALLENGES — "What's holding you back", redesigned per Figma node 3278:8691 into
   one green rounded card (was two outlined columns, each with its own small-caps
   label above a separate paragraph). Both items now read as a single running
   paragraph each, with the old per-item label repurposed as an inline bold lead
   phrase (.challenges-lead) followed by the faded rest (.challenges-rest) — same
   two data fields (c.label/c.text), no data-model change. */
/* Solid black card, white text — the pain-point page reads as a deliberate dark
   beat against the rest of the (light) deck. Same bold-lead/faded-rest hierarchy
   as before, just inverted for a dark fill instead of collapsing to flat white. */
.challenges-card{max-width:589px;margin:0 auto;background:#000;border-radius:10px;padding:20px;text-align:center;}
.challenges-card .proposal-microlabel{margin-bottom:14px;color:#fff;}
.challenges-item{font-family:"Project X",sans-serif;font-weight:200;font-size:22px;line-height:25px;margin:0 0 14px;text-align:left;}
.challenges-item:last-child{margin-bottom:0;}
.challenges-lead{font-weight:inherit;color:#fff;}
/* Same treatment as needsOverview's .col-text-rest (solid, 700, 1.2) — white
   instead of black since this sits on the black card. Lead/rest contrast is
   weight-only here too now (200 lead / 700 rest), not colour. */
.challenges-rest{font-weight:700;line-height:1.2;color:#fff;}

/* APPROACH METHOD — 3-column pitch grid */
.approach-method{margin:var(--space-6) 46px 0;}
/* Pill → paragraph gap is a consistent 52px (Our solution / What our clients say /
   Results you can expect all match). */
.approach-pill-wrap{display:flex;justify-content:center;margin-bottom:52px;}
/* Brief header — same size/position as the "Our solution" pill, but no outline
   stroke and title case (uses the .pill base, drops the border/uppercase). */
.brief-header{text-transform:none;font-weight:700;}
.approach-cols{display:grid;grid-template-columns:repeat(3,1fr);column-gap:var(--space-4);row-gap:var(--space-4);}
.approach-col-head{font-family:"Project X",sans-serif;font-weight:700;font-size:11px;letter-spacing:2px;text-transform:uppercase;line-height:1.3;color:#000;margin-bottom:0;}
.approach-col-text{font-family:"Project X",sans-serif;font-weight:700;font-size:12.8px;line-height:1.2;color:rgba(0,0,0,0.4);}
/* Our Process — reuses the timeline's own module-card language (.tl-module,
   .tl-module-edge date chip, .vt-rail) instead of a bespoke layout: a rail line
   of 3 stacked cards, a step number ("01"/"02"/"03") where a module would show
   a date. Always open, no toggle — there's nothing to expand, so no button. */
.process-vt{max-width:600px;}
/* Timeline's own rail starts at 78px to clear ITS title row; here the pill above
   is the only thing before it, so the rail starts at the very top of this box. */
.process-vt .vt-rail{top:0;}
.process-module .tl-row.mod-head{cursor:default;}
/* Real timeline modules dim their name/toggle on hover as a "click to expand"
   affordance (see .tl-row.mod-head:hover above) — Our Process cards are
   always open with nothing to expand, so that hint doesn't apply here. */
.process-module .tl-row.mod-head:hover .module-name{opacity:1;}
.process-module .tl-module-body{padding:0 24px 24px;}
.process-module .approach-col-text{font-size:16px;max-width:500px;margin:0 auto;}
/* The card itself hugs its own content width instead of stretching to fill
   the rail's full width, now that the text inside is capped at 500px —
   .tl-module-edge (the "01" step chip) centres on ITS OWN parent (this
   card, left:50%), so shrinking the card and re-centring it with margin:auto
   still lands the chip on the rail's centre line, not off it.
   Compound selector, not just .process-module: .tl-module's own margin:12px
   0 (below) sets left/right to explicit 0, not auto, and — same single-class
   specificity — wins on source order alone since it comes later in the
   file. The 2-class selector here beats it regardless of order, while still
   keeping that rule's 12px vertical rhythm (only auto-centering overrides
   the horizontal 0). */
.tl-module.process-module{max-width:548px;margin:12px auto;}
/* Unlike the real timeline (where only .tl-module's OWN flat fill sits behind
   .vt-rail — see the ::before split above the base .tl-module rule — while the
   card's content still shows over the rail), Our Process wants a plain solid
   card with the rail hidden behind it entirely, content included. Giving
   .process-module its own positive z-index (needs position:relative, already
   inherited from .tl-module) makes it establish its OWN stacking context — the
   whole card, fill and content together, then paints as one atomic unit above
   .process-vt's rail, regardless of the ::before's z-index:-1 *within* that
   context. Compound selector (2 classes) so it doesn't affect the real timeline's
   .tl-module, which has no z-index of its own to override. */
.tl-module.process-module{z-index:1;}

/* CLIENT QUOTE GALLERY */
.quote-gallery{background:#F5F5F5;border-radius:16px;padding:50px 46px;}
.quote-slides{position:relative;}
.quote-slide{display:none;}
.quote-slide.is-active{display:block;}
.quote-text{font-family:"Project X",sans-serif;font-size:22px;font-weight:700;line-height:1.2;color:rgba(0,0,0,0.4);}
.quote-byline{margin-top:20px;font-family:"Project X",sans-serif;font-weight:700;font-size:9px;letter-spacing:2px;text-transform:uppercase;color:#000;}
.quote-dot-row{display:flex;justify-content:center;gap:4px;margin-top:36px;}
.quote-dot{width:6px;height:6px;border-radius:3px;background:rgba(0,0,0,0.15);cursor:pointer;overflow:hidden;transition:width .3s ease;}
.quote-dot.is-active{width:24px;background:rgba(0,0,0,0.08);}
.quote-fill{display:block;height:100%;width:0%;background:#000;border-radius:3px;}
.quote-dot.is-active .quote-fill{animation:quote-fill 12s linear forwards;}
@keyframes quote-fill{from{width:0%;}to{width:100%;}}

/* BACK COVER — fills the whole slide (flex:1, same trick as the green statement
   blocks), its own content centred both ways as one tight stack: the headline,
   then a single module holding every action (Request/Open the Scope, Book a
   meeting, Download) directly beneath it. */
.back-cover{position:relative;flex:1 1 auto;width:100%;min-height:0;padding:20px;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center;}
.back-cover-text{width:100%;font-family:"Project X",sans-serif;font-size:40px;font-weight:200;letter-spacing:-1.2px;color:#000;}
/* MAIN BUTTON — the standalone-command family, as distinct from lozenges
   (which are compact and live in a dense/clustered row of siblings — nav
   tabs, tags, in-row triggers). A main button is a freestanding verb:
   .back-cover-btn .pdf-btn .action-btn .sigbtn
   .admin-bar-save .os-claude-btn .os-linkbtn .os-upload-primary
   No unified height set yet (unlike --lozenge-h) — sizes currently vary by
   context (14px/36px down to 8px/16px padding); revisit if/when asked to
   converge these too. See styleguide.html for live samples — keep in sync. */
.back-cover-btn{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;background:var(--accent);color:#000;border:none;border-radius:6px;padding:14px 36px;cursor:pointer;transition:opacity .2s,background .2s;}
.back-cover-btn:hover{opacity:.85;}
/* Request Scope / Book meeting / Download, all in one row, directly under the
   headline — replaces the old two-tier layout (actions 200px down, icon
   pinned to the slide's bottom edge) with a single minimal module. */
.back-cover-module{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;margin-top:82px;}
.back-cover-btn-grey{background:rgba(0,0,0,0.08);}
.back-cover-btn-grey:hover{opacity:1;background:rgba(0,0,0,0.14);}
.back-cover-iconbtn{display:inline-flex;align-items:center;gap:8px;height:44px;padding:0 20px;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;border:none;border-radius:6px;background:rgba(0,0,0,0.08);color:#000;cursor:pointer;transition:background .2s,color .2s;white-space:nowrap;}
.back-cover-iconbtn:hover{background:rgba(0,0,0,0.14);}
.back-cover-iconbtn svg{width:16px;height:16px;display:block;flex:none;}

/* ══ SLIDE PROPOSAL — a vertical deck ══
   Every section is a slide: at least one viewport tall, its content centred both
   ways, with ONE consistent responsive gap to the browser edge on any screen.
   Green statement blocks fill the slide inside that gap. No snap/lock at all —
   a plain continuous scroll through the deck, smooth and constant, rather than
   settling onto each slide. Nothing is cut — a tall section just flows. */
:root{--slide-gap:20px;}
/* The proposal deck runs full viewport width (not the centred 900px page), so
   slides and their green blocks reach the browser edge. */
.page-proposal{width:100%;max-width:100%;}
/* The grey "bar" was elastic overscroll: scrolling past the real top/bottom of
   the deck (trackpad rubber-band) briefly exposes html/body's own grey behind
   the content — the intro slide visibly sliding DOWN on an upward scroll at
   the very top, then snapping back. Neither recolouring the nav nor the page
   fixed it (both tried above, both reverted) because the actual page
   background is meant to stay grey — this stops the bounce itself, on both
   axes and on both the scrolling element (html) and body (WebKit/Safari
   honour it on either depending on which it treats as the root scroller —
   setting both is the only way to be sure), so there's nothing beyond the
   deck's real start/end to ever scroll — let alone bounce — into view. */
html.snap-proposal,html.snap-proposal body{overscroll-behavior:none;}
html.snap-proposal{scroll-behavior:smooth;}
/* Each display section is wrapped in a .prop-slide: one viewport tall, its
   content centred both ways, with a fixed 20px gap to the browser edge. */
.page-proposal .prop-slide{
  min-height:100vh;min-height:100svh;box-sizing:border-box;
  padding:var(--slide-gap);
  display:flex;flex-direction:column;justify-content:center;align-items:center;
}
/* Kill every legacy inter-section margin — the slide handles all spacing now. */
.page-proposal .prop-slide>*{margin:0!important;}
/* Green statement slides keep 20px on the sides but 52px top/bottom, so the block
   clears the sticky menu (top) and the fixed credit lozenges (bottom). */
.page-proposal .prop-slide:has(.approach-proposal){padding-top:52px;padding-bottom:52px;}
/* Page 4 (challenges) — a dark vignette behind the now-black challenges-card: solid
   black through the middle, fading to transparent (back to the page's own bg) within
   100px of the top and bottom edges. */
.page-proposal .prop-slide:has(.challenges-card){
  background:linear-gradient(to top, transparent 0, #000 100px, #000 calc(100% - 100px), transparent 100%);
}
/* Page 6 (modules/"Our recommended project") — genuinely transparent (0% opacity,
   not solid white) at both edges, so it blends into the page's own grey behind
   it as a real vignette, fading into a solid-white plateau spanning the middle
   40% (30%–70%) rather than a single peak at the midpoint. Used to also carry
   an explicit white background-color, papering over the sticky topnav showing
   a flat grey bar as this slide's transparent top scrolled underneath it —
   that turned out to be elastic overscroll (see the overscroll-behavior rule
   above) plus the intro slide's own gap (see .prop-slide-intro), both now
   fixed at the source, so the fade here is free to actually reach 0% again. */
.page-proposal .prop-slide:has(.modules-section){
  background-image:linear-gradient(to bottom, transparent 0%, #fff 30%, #fff 70%, transparent 100%);
  /* Stays vertically CENTRED like every other slide so the deck's scroll rhythm
     is even (top-aligning this one made it hug the slide before it and leave a
     gap before the next). The module-open "jump" that centering causes — the
     slide re-balances around its taller centre, shifting the clicked card up
     even though scrollY never moves — is instead compensated in JS: the toggle
     handler measures the clicked card's viewport Y before/after render and
     scrollBy's the delta, pinning it in place. See the data-toggle handler. */
}
/* Green statement blocks fill the slide inside the gap, text centred — the same
   shape-agnostic card on any screen size. */
.page-proposal .prop-slide .approach-proposal{
  flex:1 1 auto;width:100%;min-height:0;
  display:flex;flex-direction:column;justify-content:center;align-items:center;gap:0;
  padding:clamp(28px,6vmin,72px);border-radius:16px;
}
.page-proposal .prop-slide .approach-text{text-align:center;max-width:22em;}
/* Non-green slides: centred content, capped width so it breathes on wide screens. */
.page-proposal .prop-slide>.approach-method,
.page-proposal .prop-slide>.modules-section,
.page-proposal .prop-slide>.quote-gallery,
.page-proposal .prop-slide>.back-cover{width:100%;max-width:900px;}
.page-proposal .prop-slide .modules{gap:20px;}
/* Cover slide — the project name gets real presence, not the 18px inline size. */
.page-proposal .prop-slide .hero-title-sm{font-size:clamp(30px,5.2vmin,56px);font-weight:200;letter-spacing:-0.02em;line-height:1.05;max-width:16em;}
/* pill headlines in proposal */
.page-proposal .pill-outline{font-weight:700;}
@media print{
  html.snap-proposal{scroll-behavior:auto;}
  .page-proposal .prop-slide{min-height:0!important;display:block!important;padding:0 0 48px!important;}
  .page-proposal .prop-slide .approach-proposal{display:block;padding:32px!important;}
  /* Back cover's on-screen layout centres itself inside a full-height flex
     slide — print forces slides back to normal block flow (above), so
     .back-cover needs the same: plain block, module following the headline
     in normal flow rather than trying to vertically centre on a page. */
  .back-cover{display:block!important;padding:32px!important;}
}

/* PHASES — group outside modules */
.modules{margin:0 46px;display:flex;flex-direction:column;gap:20px;}
.modules-section{margin-top:var(--space-6);}
.phase-group{display:flex;flex-direction:column;gap:10px;}
.phase-modules{display:flex;flex-direction:column;gap:20px;}
.phase-sep{display:flex;justify-content:center;padding:8px 0;}
/* An optional phase's own commit bar (phaseCommitBar, app.js) is a GATE, not a
   module — a mid-layer between two real modules that has to be addressed
   before the ones after it continue. It wears the exact same .module card
   shell as the work it sits between (so it reads as one language of cards,
   not a banner bolted between them), just at half the collapsed height —
   .phase-gate-top is 40px against .modules-section .module-top's 80px — and
   with a plain "Phase N" + fee/status header standing in for a full module's
   icon+name, since a gate doesn't have creative-work content of its own to
   preview. The "+" (same .tl-toggle every module uses, same data-toggle
   mechanism) opens the same explanation + sign-off this always carried, it's
   just no longer the first thing forced onto the page. Three states:
   .phase-gate.is-locked    — previous phase unfinished, nothing to decide
                              yet: recessive, no toggle (nothing to expand to).
   .phase-gate.is-ready     — the decision is live now: the one state that
                              should draw the eye, same mint accent
                              (#F6FFEB) used everywhere else a live decision
                              sits (.approach-proposal).
   .phase-gate.is-committed — settled history: the module default (flat,
                              #F8F8F8) — still expands, now to the signed record. */
.phase-commit-msg{display:block;font-family:"Project X",sans-serif;font-weight:500;font-size:13px;line-height:1.4;color:rgba(0,0,0,0.4);margin-bottom:16px;}
.modules-section .phase-gate .phase-gate-top{height:40px;padding:0 20px;cursor:pointer;}
.phase-gate.is-locked .phase-gate-top{cursor:default;}
.phase-gate-name{font-family:"Project X",sans-serif;font-weight:500;font-size:14px;color:#000;}
.phase-gate-fee{font-family:"Project X",sans-serif;font-size:10px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.45);}
.modules-section .phase-gate.is-ready{background:var(--accent);}
.phase-gate.is-ready .phase-gate-fee{color:#000;}
.phase-gate.is-locked{opacity:0.6;}
.modules-section .phase-gate .phase-gate-body{display:block;padding:20px;border-top:0.5px solid rgba(0,0,0,0.08);}
.phase-gate-body .final-sign{margin:0;border:none;padding:0;}
/* .sigbtn's default (clickable, unsigned) fill is the accent colour — invisible
   as a button against .is-ready's own accent card. .done/.locked already carry
   guaranteed-contrast fills of their own (solid black / near-transparent) and
   must stay excluded, or this would un-mute the "awaiting" state instead. */
.phase-gate-body .sigbtn:not(.done):not(.locked){background:#000;color:#fff;}
.phase-gate-body .sigbtn:not(.done):not(.locked):hover{background:#000;opacity:.85;}
/* The modules under an optional phase nobody's committed to yet read as not
   yet the client's — same fade language used elsewhere for "not decided". */
.phase-uncommitted .phase-modules{opacity:0.5;}

/* TIER 2 GATE — a module's own sign-off (tlGateBand/gateBand, app.js).
   Redesigned 2026-09-02 to be "much more subtle": just another row on the
   rail (same .tl-bar/.tl-seg-l/-c/-r grid every task uses — row invariant
   01 still holds, the rail runs straight through it) rather than a bespoke
   full-width card, and it renders NOTHING until canSign — no waiting/locked
   state to explain, the row simply isn't there yet.
   .tl-gate-signbtn — unsigned + ready: an accent lozenge, "Sign to
   complete", on both sides. One click always opens the same signature
   dialog every Deed/Gate shares (data-signopen/data-matasign) — the hold
   gesture that used to live in this row now happens inside that dialog.
   .tl-gate-signed — once signed: plain text, "Signed by <name>", sitting
   in tl-seg-l (right-aligned toward the rail, MATA's side) or tl-seg-r
   (left-aligned, the client's) — the same alignment every task row's own
   labels already follow. */
.tl-gate-signbtn{height:var(--lozenge-h);padding:0 16px;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;background:var(--tl-live);color:#000;border:none;cursor:pointer;transition:background .15s;}
.tl-gate-signbtn:hover{background:var(--tl-live-hover);}
.tl-gate-signed{font-family:"Project X",sans-serif;font-size:12px;color:rgba(0,0,0,0.4);}
/* Plain text has no chip of its own to keep it off the rail (unlike
   .tl-gate-signbtn's lozenge) — 20px clearance on whichever side actually
   faces the rail: MATA's copy sits in tl-seg-l (right-aligned, so the gap
   goes on its right), the client's in tl-seg-r (left-aligned, gap on its left). */
.tl-seg-l .tl-gate-signed{padding-right:20px;}
.tl-seg-r .tl-gate-signed{padding-left:20px;}
/* Press-and-hold — a filling bar under the label reads as "hold this", not a
   circular spinner (that motif already means "loading" elsewhere in the app).
   Held the full HOLD_MS (app.js), the fill completes and commits; released early,
   the same transition reverses in 120ms — cancelling needs no separate animation,
   it's just the fill un-happening. Still used inside the signature dialog itself
   (signModal) as its confirm control — every tier commits the same way. */
.tl-holdbtn{position:relative;overflow:hidden;width:100%;font-family:"Project X",sans-serif;font-weight:500;font-size:11px;letter-spacing:0.3px;text-transform:uppercase;background:rgb(228,230,227);color:#000;border:none;border-radius:6px;padding:10px 14px;cursor:pointer;user-select:none;touch-action:none;}
.tl-holdbtn:disabled{opacity:0.4;cursor:default;}
.tl-holdbtn-fill{position:absolute;inset:0;background:rgba(0,0,0,0.16);transform:scaleX(0);transform-origin:left;transition:transform 120ms linear;}
.tl-holdbtn.is-holding .tl-holdbtn-fill{transition-duration:900ms;transform:scaleX(1);}
.tl-holdbtn-label{position:relative;}
@media (prefers-reduced-motion:reduce){
  /* No fill to hold through — holdStart()/the keydown listener (app.js) both bail
     out under reduced motion, so .is-holding never actually gets applied here; this
     is just insurance against the class landing some other way. */
  .tl-holdbtn-fill{transition:none!important;}
}

/* MODULES — 10px rounded */
.module{background:#fff;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;overflow:hidden;}
.module-top{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;gap:16px;cursor:pointer;}
.module-top.static{cursor:default;}
.module-top-left{display:flex;align-items:center;gap:14px;}
.module-icon{width:44px;height:44px;flex-shrink:0;display:flex;align-items:center;justify-content:center;}
.module-icon svg{width:44px;height:44px;}
.module-name{font-family:"Project X",sans-serif;font-weight:200;font-size:20px;letter-spacing:-0.2px;color:#000;text-align:center;}
.module-top-right{display:flex;align-items:center;gap:8px;flex-shrink:0;}
.module-weeks{font-family:"Project X",sans-serif;font-size:10px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.25);}
.module-cost{font-family:"Project X",sans-serif;font-size:10px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;color:#000;}

/* Proposal/Scope modules — match timeline icon size, toggle, palette */
.modules-section .module{background:#F8F8F8;border-color:transparent;position:relative;}
/* Same off-white/no-border variant, reused for the record box's People card
   (os.js) so it reads as distinct from Link's plain white without a label
   saying so — document-first-admin-surface-prompts.md. */
.module.is-people{background:#F8F8F8;border-color:transparent;}
.modules-section .module-top{height:80px;padding:0 20px;gap:0;position:relative;}
/* Scope configurator — the client tunes the recommended project */
.mod-remove{position:absolute;left:56px;top:50%;transform:translateY(-50%);width:var(--lozenge-h);height:var(--lozenge-h);display:inline-flex;align-items:center;justify-content:center;border:none;background:transparent;color:rgba(0,0,0,0.25);font-size:15px;line-height:1;cursor:pointer;border-radius:5px;opacity:0;transition:opacity .2s,color .2s;}
.module:hover .mod-remove{opacity:1;}
.mod-remove:hover{color:#000;}
@media (hover:none){.mod-remove{opacity:.3;}}
.modules-section .module-top .module-name{flex:1;text-align:center;}
/* Proposal module card — icon left (abs), centred name, meta right:70px (abs), toggle right:23px (abs) */
.mod-prop-meta{position:absolute;right:70px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;align-items:flex-end;gap:2px;}
/* Scope module card (moduleCard(), .module-top--flow) — SAME .tl-mod-icon/.tl-toggle
   classes as the proposal card above and the timeline's own mod-head, but laid out as
   a plain flex row instead: icon · centred name (flex:1 above) · weeks/cost/toggle
   cluster. Both classes carry absolute positioning meant for a row where they're the
   ONLY other things sharing it with the name — here weeks/cost sit in normal flow
   right alongside the toggle, so the inherited position:absolute was landing the icon
   over the name's own left edge and the toggle over weeks/cost, all pinned to the same
   handful of pixels. Restoring static flow here fixes the leak without touching either
   of the two contexts that already work correctly around it. */
.module-top--flow .tl-mod-icon{position:static;transform:none;}
.module-top--flow .tl-toggle{position:static;transform:none;}
/* .module-name's flex:1 (base rule above) centres it in whatever space is LEFT
   after its real flex siblings — icon on one side, the weeks/cost/toggle
   cluster on the other — and those two are never the same width (the meta
   cluster is reliably wider), so the centred text drifts toward the icon
   side instead of sitting on the card/page's own centre line. Taking it out
   of flex flow and centring it on the full row directly (same trick
   moduleCardProposal's .mod-prop-meta already relies on) fixes that
   regardless of how wide either sibling ends up. */
.module-top--flow{position:relative;}
.module-top--flow .module-name{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);flex:none;}
/* .modules-section .module-top's own gap:0 (above) assumed icon/toggle were both
   absolutely positioned (gap never applied to them) — restore breathing room now
   that the icon is a real flex participant here. Matches .module-top-left's own
   icon-to-text gap elsewhere in this same file. */
.module-top--flow{gap:14px;}
/* Plain small-caps section label (no pill/outline chrome) — shared by needsOverview
   and the challenges card, both redesigned from Figma to drop the pill-outline label
   treatment in favour of bare text. Distinct from .approach-label/.col-label, which
   are their own established sizes used elsewhere. */
.proposal-microlabel{font-family:"Project X",sans-serif;font-weight:500;font-size:13.36px;line-height:10.7px;letter-spacing:0.534px;text-transform:uppercase;color:#000;}

/* What you need / why you need it — stacked (was 2 side-by-side columns), same
   589px width as page 4's challenges-card, no card/border of its own. */
.needs-overview{display:flex;flex-direction:column;gap:40px;width:100%;max-width:589px;margin:10px auto 0;text-align:center;}
.needs-overview-item{flex:none;}
.needs-overview-item .proposal-microlabel{margin-bottom:16px;}
/* Body copy stays 26px/30px line-height (Figma node 3278:8684). Contrast between
   the lead phrase and the rest is now weight-only, not colour — both solid black:
   the lead is Mata_02 (200, the same light weight as the paragraph default), the
   rest is bolder (700, matching .approach-col-text's weight elsewhere) — reversed
   from an earlier pass that had this backwards (bold lead/faded rest). */
.needs-overview .col-text{font-family:"Project X",sans-serif;font-size:26px;line-height:30px;font-weight:200;color:#000;text-align:left;}
.needs-overview .col-text .col-text-lead{color:#000;font-weight:200;}
.needs-overview .col-text .col-text-rest{color:rgba(0,0,0,1);font-weight:700;line-height:1.2;}
.module-body{display:grid;grid-template-columns:1fr 1fr;border-top:0.5px solid rgba(0,0,0,0.08);}
.module-col{padding:20px 20px 28px;}
.module-col+.module-col{border-left:0.5px solid rgba(0,0,0,0.08);}
/* Fixed box height + flex-centred text, not line-height — this custom font's
   line-height resolves inconsistently depending on flex-sibling count (30px
   solo vs 15px next to a button, same element, same computed font-size —
   even pinning line-height numerically didn't close the gap, so this sidesteps
   line-height calculation entirely with a hard box height instead), so any
   two headers render at the same height despite sharing this exact class,
   button or no button beside them. */
.col-label{font-family:"Project X",sans-serif;font-weight:700;font-size:10px;letter-spacing:2px;text-transform:uppercase;color:#000;margin-bottom:0;height:15px;display:flex;align-items:center;}
.col-text{font-family:"Project X",sans-serif;font-size:12px;font-weight:700;line-height:1.2;color:rgba(0,0,0,0.4);}


/* BUTTONS — solid light grey; done = solid black (consistent) */
.sigbtn{font-family:"Project X",sans-serif;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;padding:9px 18px;border:none;background:var(--accent);color:#000;border-radius:5px;cursor:pointer;transition:background .25s ease,color .25s ease;}
.sigbtn:hover{background:#D8E0CF;}
.sigbtn.signed{background:#000;color:#fff;}
.sigbtn.wide{width:100%;margin-top:12px;padding:13px;}
.sigbtn.done{font-family:"Project X",sans-serif;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;background:#000;color:#fff;padding:9px 18px;border-radius:5px;cursor:default;}
.sigbtn.locked{font-family:"Project X",sans-serif;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;padding:9px 18px;border:none;background:rgba(0,0,0,0.04);color:rgba(0,0,0,0.2);border-radius:5px;cursor:not-allowed;}
.sigbtn.wide.done{width:100%;margin-top:12px;padding:13px;text-align:center;}

/* ====== TIMELINE ======
   Faithful to Figma 3127:10273. Content lives in a fixed 780px centred column.
   Type ramp: dates = Mata_04 (w400) 7px, labels/names = Mata_05 (w500), pills radius 5. */
/* --tl-loz-h ties the task-lozenge height AND the vertical gap between rows
   together: the gap equals one lozenge height, so a row is 2× tall. */
/* z-index:0 (not just position:relative) is load-bearing: it's what makes .vt its
   own stacking context, so .tl-module's negative z-index (behind .vt-rail) stays
   scoped to sitting behind the rail specifically — without it, .tl-module escapes
   to whatever the nearest ANCESTOR stacking context is instead (the page, in
   practice), vanishing behind far more than just the rail. */
/* Timeline-scoped live green — deliberately its OWN token, not --accent
   (used in 20+ other places app-wide: repainting --accent would repaint the
   proposal page and the OS cockpit along with it). */
.vt{position:relative;z-index:0;width:780px;max-width:100%;margin:0 auto;--tl-loz-h:var(--lozenge-h);--tl-task-h:40px;--tl-live:#edffd7;--tl-live-hover:#dbedc7;}
.vt-rail{position:absolute;left:calc(50% - 0.25px);top:78px;bottom:0;width:0.5px;background:rgba(0,0,0,0.1);z-index:0;}

/* Base row pitch = two lozenge-heights + 15px extra vertical gap between every date
   lozenge down the timeline. Content (joined bar / node date) centres on the rail;
   action buttons overlay the outer edges absolutely. */
/* Task chips are now taller (--tl-task-h, 40px) than the date/lozenge chips
   (--tl-loz-h, 25px) that share the row — height = task chip + one lozenge
   of trailing gap + the original 15px extra, so the gap between rows stays
   the same 15px it always was rather than scaling with the taller content. */
.tl-row{position:relative;height:calc(var(--tl-task-h) + var(--tl-loz-h) + 15px);display:flex;align-items:center;justify-content:center;}

/* Header — the project's own title, centred, then a 100px gap before the timeline
   starts. The "MATA × Client" line that used to sit above it was removed. */
.tl-titlerow{display:flex;flex-direction:column;justify-content:center;align-items:center;margin-bottom:100px;}
.tl-project-title{font-family:"Project X",sans-serif;font-weight:500;font-size:30px;letter-spacing:0.2px;color:rgba(0,0,0,1);}

/* Date lozenge — Mata_04 / w400 / 7px, fixed 15px tall pill. Same grey/black family as the
   task chips: future (default) = 50% opacity, complete (past) = full strength. */

/* Register-mark tick — sits on the rail below a milestone lozenge, ticks left/right like the module icons */
/* (rail-tick register-mark dashes removed — the divider is now a bare spacer with the rail running through) */
/* +15px so the gap between one module's end-date and the next module's start-date
   (was 23px) matches the deliberate 15px added to in-module row spacing — now 38px. */
.tl-row.tl-railtick{height:39px;}

/* Node labels — sit inside the same chip as the date (see tlDatePill's label
   param), not a separate lozenge beside it, so Kick-off/Finish read as one
   pill rather than two things glued together. */
.vt-nlabel{font-family:"Project X",sans-serif;font-size:11.5px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.4);margin-left:8px;}

/* Closing statement at the very end of the timeline — the same "Results you can
   expect" sentence (project.outcome) as the proposal, restated once the timeline
   itself ends. The start/end gate bars this used to sit under (.tl-gate) were
   removed outright — same class of "reads as a button but isn't" complaint as the
   gates themselves, so simpler to drop them than keep restyling them. Styled like
   an ordinary module-edge date (.tl-module-edge .tl-chip-date) — page-bg fill +
   border, not a solid chip fill — fixed 300px box instead of a plain paragraph.
   Line-height is looser than a date's (which never wraps) since this is always
   multiple lines at 9px in a 300px box. */
.tl-gate-outcome{width:300px;margin:28px auto 0;background:#F0F2EF;border:0.5px solid rgba(0,0,0,0.12);border-radius:5px;padding:16px 20px;text-align:center;}
.tl-gate-outcome p{margin:0;font-family:"Project X",sans-serif;font-weight:400;font-size:12px;letter-spacing:0.35px;line-height:1.2;color:#000;}

/* Module box — same card chrome as Scope (.module), sub-milestones swap in for the body.
   The rail needs to read differently against the card's flat fill than against its
   own content: still threading visibly through the plain background (so it reads as
   one continuous spine down the page), but sitting BEHIND every lozenge/chip/date so
   the rail never visibly cuts across text or icons. A single z-index on .tl-module
   can't do both at once — z-index only has meaning relative to siblings OUTSIDE a
   stacking context, so as long as the module (background AND content together) is
   one stacking context, the rail is either fully in front of or fully behind the
   whole thing. Fix: the flat fill moves onto ::before (position:absolute, z-index:-1,
   escapes to .vt's own stacking context since .tl-module itself no longer sets
   z-index) — it alone sits behind the rail. .tl-module's real children (edges,
   header, body rows, chips) keep no z-index of their own, so they land in the
   normal/auto paint layer alongside — and after, so on top of — .vt-rail. */
.tl-module{position:relative;margin:12px 0;overflow:visible;background:none;border:none;}
.tl-module::before{content:"";position:absolute;inset:0;z-index:-1;background:#F0F2EF;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;}
/* The live module gets a 30% accent-green fill instead of the plain page-bg grey —
   same tint whether the card is open or closed, since both states share this class. */
.tl-module.tl-module-live::before{background:rgba(246,255,235,0.3);}
.tl-module .tl-row{padding:0 20px;}
.tl-module-body{padding-bottom:24px;}
/* Locked dims the module's OWN content (header/body), never its edge dates —
   opacity on a parent caps what's visible inside it no matter what opacity a
   child sets, so the edge dates must simply not be a descendant of the dimmed
   element's opacity in the first place. Edge dates are boundary markers driven
   only by .is-past (see tlDatePill()/V=77) regardless of the module's own
   locked/live/done state — same rule as everywhere else in the timeline.
   The rule for the module's OWN header, corrected: uncompleted (locked OR
   live — not finished yet) reads full strength, exactly like an uncompleted
   task row; completed (done) fades back, exactly like a completed task row.
   A prior version of this dimmed LOCKED modules instead of DONE ones —
   backwards from "uncompleted = not faded, completed = faded" — fixed here. */
.tl-module-done .tl-row.mod-head{opacity:0.4;}
/* (Rail continuation removed — the card is transparent now, so the global
   .vt-rail shows through directly. A per-card ::before would double the line.) */

/* Start/end date lozenges straddle the module card's top and bottom edge,
   centered on the rail — same pill, same position, whether the module is
   open or collapsed (previously the open state swapped to a blank 30px
   circle/square with the date text hidden, which read as misaligned). */
.tl-module-edge{position:absolute;left:50%;z-index:5;}
.tl-module-edge-start{top:-0.5px;transform:translate(-50%,-50%);}
.tl-module-edge-end{bottom:-0.5px;transform:translate(-50%,50%);}

/* Module head — icon hard-left, name centred on the rail, toggle hard-right.
   Same 80px band, same layout, open or closed — name never hides, icon/toggle
   never move, so the header reads as one stable anchor regardless of state. */
.tl-row.mod-head{display:block;position:relative;height:80px;cursor:pointer;}
.tl-row.mod-head:hover .module-name,.tl-row.mod-head:hover .tl-toggle{opacity:0.45;}
.tl-mod-icon{position:absolute;left:23px;top:50%;transform:translateY(-50%);width:24px;height:24px;}
.tl-mod-icon svg{width:24px;height:24px;display:block;}
.tl-row.mod-head .module-name{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:inline-flex;align-items:center;gap:7px;}
/* Neutral, not alarmed — a fact ("the date passed"), not a warning colour. Same grey
   family as the gate band's own waiting state, not red/amber — see moduleIsOverdue()
   and the client-visible tone decided for it. */
.tl-mod-overdue{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.4px;text-transform:uppercase;color:rgba(0,0,0,0.35);background:rgba(0,0,0,0.06);border-radius:5px;padding:5px 8px;white-space:nowrap;}
/* Toggle — a real button, styled like the timeline's other icon buttons
   (.tl-iconbtn): 25x25 grey box (--lozenge-h), not a bare icon floating with
   no fill. It's a visual affordance for the whole row's click (data-tltoggle
   sits on .tl-row.mod-head), but reads as "the button for this action" the
   same way .tl-iconbtn does elsewhere in the timeline. */
/* Bare icon by default — the grey lozenge box only appears on hover, as the
   affordance that this is a button (reverses V=84, which made it permanent). */
.tl-toggle{position:absolute;right:23px;top:50%;transform:translateY(-50%);width:var(--lozenge-h);height:var(--lozenge-h);display:flex;align-items:center;justify-content:center;color:#000;background:transparent;border-radius:5px;transition:background .15s;}
.tl-row.mod-head:hover .tl-toggle{background:#0000000f;}
.tl-toggle svg{display:block;}
/* Module name — Mata_02 / w200 / 20px, black + title case, inherited from .module-name */

/* Joined bar — label(s) + centred date butt together into ONE continuous pill.
   1fr|auto|1fr grid keeps the date dead-centre on the rail; segments meet exactly on the
   column boundaries so adjacent chips read as a single link. */
/* Centre date column is a fixed width, not auto-sized to its own text — an
   auto column still centres correctly in principle, but a fixed track
   guarantees every row's date sits at the exact same x, immune to any
   sub-pixel drift from what's in the side columns. */
/* .tl-seg no longer hard-sets a height — a label seg (40px chip) and the date
   seg (25px chip) now hold different-height content, so each seg sizes to
   its own child; align-items:center (here and on .tl-bar) keeps everything
   on one shared centreline regardless. */
/* Inset 23px each side to match the module header's own hard-left icon and hard-right
   toggle — a bound on how far a long label may run, not a position (the row's content
   is packed to the rail, so nothing normally reaches it). The .tl-row's `padding:0 20px`
   can't serve as that bound: an absolutely-positioned child resolves against the
   padding BOX and so ignores that padding entirely.
   Centre track is `auto`, not a fixed 70px: the date chip's own min-width holds
   every ordinary date to the same 70px spine, and the track only widens for a chip
   that genuinely needs it (a date RANGE — "27.07.26 – 29.07.26"). Because the two
   1fr side tracks stay equal whatever the centre measures, growing it expands the
   chip symmetrically about the rail rather than shunting it off-centre. */
.tl-bar{position:absolute;left:23px;right:23px;top:50%;transform:translateY(-50%);display:grid;grid-template-columns:1fr auto 1fr;align-items:center;}
.tl-seg{display:flex;align-items:center;min-width:0;}
/* Everything packs toward the rail, so label+date+label butt together as one piece and
   each icon lands flush against the OUTER edge of the task lozenge it belongs to —
   the icon travels with its label, it does not float out to the module's own edge.
   Row structure is `[btns][label]` on the left and `[label][btns]` on the right, so
   packing each seg toward the centre puts the icon on the far side of its own label
   automatically, at whatever x that label happens to end. */
.tl-seg-l{justify-content:flex-end;}
.tl-seg-c{justify-content:center;}
.tl-seg-r{justify-content:flex-start;}
/* Height moved off the shared .tl-chip rule onto each variant below — a
   label chip (40px) and a date chip (25px) are no longer the same height. */
.tl-chip{display:inline-flex;align-items:center;box-sizing:border-box;border-radius:5px;font-family:"Project X",sans-serif;white-space:nowrap;}
.tl-chip-label{height:var(--tl-task-h);font-weight:500;font-size:11.5px;letter-spacing:0.4px;padding:16px 10px;gap:5px;max-width:240px;overflow:hidden;text-overflow:ellipsis;}
/* The date chip is the CONSISTENT SPINE of every row — fixed width (fills the 70px
   centre track), text always centred on the rail. Its WIDTH/POSITION never varies;
   its COLOUR does, because a label + date + button on the same row read as ONE SOLID
   PIECE that takes the row's state colour (only the DOM structure is separate). The
   base fill here is the neutral grey used by standalone module-edge dates (which sit
   outside any task row); the state rules below override it for in-row dates. */
.tl-chip-date{height:var(--tl-loz-h);font-weight:400;font-size:8.05px;line-height:8px;letter-spacing:0.35px;padding:7px 10px;width:auto;min-width:70px;box-sizing:border-box;justify-content:center;background:#0000000f;color:#000;}
/* Our Process (proposal page) reuses this same chip for its step-number edge
   lozenges — see process(), app.js — but "all text on the timeline" (the +15%
   bump above) means the real Timeline specifically, not everywhere this class
   happens to be reused. Restores the pre-bump size there alone. */
.process-vt .tl-chip-date{font-size:8px;}
/* A date carrying a time (see tlRow()/app.js) stacks date-over-time. It FILLS
   the 70px centre track rather than sitting at Figma's own 53px inside it:
   the chips either side butt straight up against the date to read as one
   continuous pill, so a narrower stack just opens an 8.5px gap on each side
   and visibly breaks that join. Figma's 53px is the width of that isolated
   node, not a spine measurement — the 70px track is the timeline's shared
   spine that every other row's date already aligns to, so matching it is
   what actually preserves the design intent. 25px date + 1px gap + 14px time
   = 40px, the same height as a task label chip (--tl-task-h), so Prompt 1's
   row-height math already fits it with no further change. */
.tl-chip-datetime{display:flex;flex-direction:column;gap:1px;}
.tl-chip-datetime .tl-chip-date{width:100%;}
.tl-chip-time{height:14px;font-weight:400;font-size:6.9px;line-height:8px;letter-spacing:0.3px;padding:3px 8px;width:100%;min-width:0;box-sizing:border-box;justify-content:center;background:#0000000f;color:#000;}
/* text-overflow doesn't apply directly to a flex container (no line box to clip) —
   dates never overflow 70px so this never mattered before, but an open module's
   name can (see tlDatePill()/app.js), so the actual text sits in its own inner
   block-level span that CAN ellipsis-truncate correctly. */
.tl-chip-date-text{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* State colours the WHOLE joined piece (label + date + button), never one part of it.
   To-do (uncompleted) = grey fill, full strength — the work still ahead reads loudest.
   Completed & signed-off = the same grey faded back. Live ("we are here") = accent green,
   solid. (Reversed from the original past-solid / future-faded scheme.) */
/* Completed is a real colour pair (#00000007 fill / #0000004d text), NOT a solid chip
   faded by opacity. Opacity dimmed the whole element — fill, text and any icon
   together — so the fill drifted toward whatever sat behind it (the live module's
   green tint vs the plain card) and the row read as a different grey per module.
   Setting the two values directly fixes the completed row to one tone everywhere,
   and lets the icon lozenge carry the identical pair (see below) rather than
   inheriting a second, compounding fade. */
.tl-incomplete .tl-chip{background:#0000000f;color:#000;}
.tl-complete .tl-chip{background:#00000007;color:#0000004d;opacity:1;}
.tl-live .tl-chip{background:var(--tl-live);color:#000;}
.tl-live:hover .tl-chip{background:var(--tl-live-hover);}
/* Standalone module-edge dates aren't inside a .tl-row, so the state rules above
   never reach them — .is-past (set per-date in tlDatePill(), app.js) fades them the
   same way a completed row's date fades, based on whether THAT DATE has passed,
   not on the enclosing module's overall completion (a live module's start date can
   already be in the past while the module itself is still ongoing). */
.tl-chip-date.is-past{background:#00000007;color:#0000004d;opacity:1;}
/* Module-edge dates are boundary markers, not buttons — an outline date (page-bg fill +
   border), same in both states. A PAST edge date is a completed milestone though, and
   should read that way: dimmed text on the SAME outline fill, not a different (solid
   grey) background — swapping to a filled look would make it read as a button, which a
   boundary marker never is. Can't reuse the generic .is-past whole-element opacity fade
   here (V=77): an edge date straddles the module card's border, half sitting over the
   opaque card and half over the bare rail/gap, so any opacity < 1 on the whole pill lets
   the rail bleed straight through the half that isn't backed by the card. Fixed by fading
   only the TEXT colour (rgba alpha) while keeping the pill itself (fill + border) fully
   opaque and identical to the future state — same faded weight, zero bleed-through,
   still reads as an outline, not a button. Higher specificity so this wins over the
   generic .is-past rule for edge dates specifically. */
.tl-module-edge .tl-chip-date{background:#F0F2EF;border:0.5px solid rgba(0,0,0,0.12);color:#000;}
.tl-module-edge .tl-chip-date.is-past{background:#F0F2EF;color:#00000057;opacity:1;}
/* Unlike an in-row date (the fixed-70px "spine" — see the comment above .tl-chip-date,
   V=52), a module-edge chip now sometimes carries the module's NAME while open, not a
   date (see tlDatePill()/app.js) — a fixed 70px column has no reason to hold here, since
   there's no column of module-edge chips that needs to align the way in-row dates do.
   Width follows its own text instead: min-width keeps a plain date looking the same size
   as before, padding replaces the in-row date's zero end-cap padding (that padding-zero
   rule assumes a fixed-width column with rail-centred text, which no longer applies).
   4-class selector so this reliably wins regardless of source order. */
.tl-module-edge .tl-chip-date.tl-end-l.tl-end-r{width:auto;min-width:70px;padding:0 14px;}
/* A node chip (Kick-off/Finish — see tlNodeRow) carries a label alongside the
   date in the same pill, so it can't be the fixed 70px spine either — same
   auto-width treatment as a module-edge chip, same reason. Padding matches
   .tl-chip-node's own 6px 14px below — this 4-class selector otherwise wins
   on specificity and was silently reverting it back to 0 top/bottom. */
.tl-chip-date.tl-chip-node.tl-end-l.tl-end-r{width:auto;min-width:70px;padding:6px 14px;}
/* Label above date, both centred — column-reverse so the DOM order (date
   then label, unchanged) still renders label on top with no JS/markup edit. */
.tl-chip-node{flex-direction:column-reverse;justify-content:center;height:auto;padding:6px 14px;gap:2px;}
.tl-chip-node .tl-chip-date-text,.tl-chip-node .vt-nlabel{text-align:center;}
.tl-chip-node .vt-nlabel{margin-left:0;}
/* Buttons ride the same piece and therefore take the same state colour as the chips
   beside them: grey to-do, accent-green live, and — including the .is-done tick — the
   completed pair. The tick used to invert to solid black-on-white on a completed row,
   which made the one element that should have receded the loudest thing in it; the
   completed row now reads as ONE uniformly quiet piece, label + date + lozenge alike. */
.tl-live .tl-iconbtn:not(.is-done){background:var(--tl-live);}
.tl-live:hover .tl-iconbtn:not(.is-done){background:var(--tl-live-hover);}
.tl-complete .tl-iconbtn,.tl-complete .tl-iconbtn.is-done{background:#00000007;color:#0000004d;}
/* The tick's own generic hover rule (.tl-iconbtn.is-done:hover, below) predates the
   completed palette and still says solid #000 — on a completed row that tied it in
   specificity with the muted pair two lines up, and source order let the black hover
   win, flashing an almost-invisible grey tick on a solid black square. One extra class
   (.tl-complete) breaks the tie so the completed row's hover darkens the same way its
   chips do (see the generic row-hover rule further down) instead of inverting. */
.tl-complete .tl-iconbtn.is-done:hover{background:rgba(0,0,0,0.12);}
/* ONE TIMELINE CONVENTION — there is no longer a separate "preview" look.
   A block of `.tl-preview …` overrides used to flatten an unsigned timeline into a
   colourless proposal: no accent green, no muted completed rows, no WE ARE HERE. It
   pre-dated the state palette below and silently won over ALL of it (every
   .tl-preview selector carries one more class than the base rule it shadows), so on
   any unsigned project — which is most of them — none of the real styling rendered.
   The states below now describe every timeline, signed or not: to-do full-strength
   grey, completed muted, live accent green. Signature status is conveyed by the
   footer's sign controls and the gate rows, not by desaturating the whole schedule.
   The .tl-preview class is still emitted (timeline(), app.js) as honest state in the
   DOM and as a hook if a signed/unsigned distinction is ever wanted again — but it
   must never be given colour rules that shadow the palette above. */
/* Figma gives EVERY chip its own 5px radius on all four corners (Timeline
   Task / Timeline Date / Timeline Time / the icon Lozenge all carry
   rounded-[5px]) — the row reads as a run of separate pills with small
   optical notches where they meet, not one continuous capsule capped only at
   its ends. The end-cap classes therefore only carry their extra 20px
   terminal padding now; the corner rounding is on .tl-chip itself (see the
   base rule above). */
.tl-chip.tl-end-l{padding-left:20px;padding-right:20px;}
.tl-chip.tl-end-r{padding-left:20px;padding-right:20px;}
/* The date keeps the rounded terminal cap but NOT the extra 20px cap padding: it is
   the rail's spine, so its text must stay dead-centre in the chip whether an end is
   capped or butts a label. BOTH sides are restated on BOTH end classes on purpose.
   Setting only the capped side (`.tl-end-l{padding-left:10px}`) leaves the opposite
   side on the 20px from `.tl-chip.tl-end-l` above — equal specificity, later rule, so
   it is not overridden — which yielded a visibly lopsided 10/20 chip. Any single-date
   lozenge must measure 10/10 whatever end classes it happens to carry. */
.tl-chip-date.tl-end-l,.tl-chip-date.tl-end-r{padding-left:10px;padding-right:10px;}
/* (pencil edit affordance removed) */

/* Action buttons sit flush against the outer end of the label chip. Figma's
   icon Lozenge keeps its own full 5px radius (as does the label beside it) —
   the squaring-off rules that used to fuse button+label+date into one capsule
   are gone, since every chip is now individually rounded. */
.tl-btns{display:inline-flex;align-items:center;gap:0;flex-shrink:0;}
.tl-iconbtn{display:inline-flex;align-items:center;justify-content:center;width:var(--tl-loz-h);height:var(--tl-loz-h);border:none;border-radius:5px;background:#0000000f;color:#000;cursor:pointer;padding:0;line-height:1;font-size:11px;}
.tl-iconbtn svg{width:10.8px;height:10.8px;display:block;}
/* Same grey the whole-row hover below uses — hovering the icon alone (a
   .tl-iconbtn is not itself a .tl-chip) must read as the identical tone, not
   a second, different grey. */
.tl-iconbtn:hover{background:rgba(0,0,0,0.12);}
/* completed answer reads as filled-in (done) rather than an open prompt */
.tl-iconbtn.is-done{background:#000;color:#fff;}
.tl-iconbtn.is-done:hover{background:#000;}
/* The whole lozenge is the hit target for its attached action, not just the icon. */
.tl-row:not(.mod-head):has(.tl-iconbtn){cursor:pointer;}
/* Hover — label + date + icon darken together as ONE piece, same as the
   to-do/complete/live state colours already do. Scoped off mod-head (the
   module header row, its own hover exists already), .tl-noderow (Kick-off/
   Finish — a boundary marker, not a task) and .tl-railtick (a bare spacer).
   Excludes .tl-live: the live row gets its own distinct hover green instead
   (see .tl-live:hover below) rather than this generic grey. .tl-complete rows
   still get this hover on top of their own muted fill/text pair — the tick
   (.is-done) is excluded here since it needs the completed palette specifically,
   not the plain grey every other icon darkens to (see .tl-complete .tl-iconbtn.is-done:hover
   above, and .tl-live's own :not(.is-done) exclusion just above that, same reason). */
.tl-row:not(.mod-head):not(.tl-noderow):not(.tl-railtick):not(.tl-live):hover .tl-chip,
.tl-row:not(.mod-head):not(.tl-noderow):not(.tl-railtick):not(.tl-live):hover .tl-iconbtn:not(.is-done){
  background:rgba(0,0,0,0.12);
}

/* A completed row that carries a viewable/downloadable result (a joined meeting,
   an uploaded file — see hoverAction, tlRow()/app.js) shows JUST a standard
   lozenge button on hover, nothing else: the row's own chips/icons fade out
   (opacity, not a recolour — see the whole-row black-invert this replaced) and
   .tl-hoveraction-label — centred over the bar — is the one thing left behind,
   same solid-black/white-text pill family as .orient-action. */
.tl-row.has-hoveraction .tl-chip,
.tl-row.has-hoveraction .tl-iconbtn{transition:opacity .12s;}
.tl-row.has-hoveraction:hover .tl-chip,
.tl-row.has-hoveraction:hover .tl-iconbtn{opacity:0;}
.tl-hoveraction-label{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:inline-flex;align-items:center;justify-content:center;height:var(--lozenge-h);padding:0 16px;white-space:nowrap;opacity:0;pointer-events:none;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:#fff;background:#000;border-radius:6px;z-index:3;transition:opacity .12s;}
.tl-row.has-hoveraction:hover .tl-hoveraction-label{opacity:1;}

/* Locked — module not yet unlocked at all */

/* ORIENTATION LINE — the system's one voice, every client view. Reads as a
   notification card (same glass language as .modal/.os-tool-pop: thin
   border, blur, soft shadow). Pinned top-left, same fixed-corner pattern as
   .mata-lozenge-fixed/.proposal-pagenum-fixed — TOP-aligned with the nav's
   own lozenge row (top:15px, matching .topnav-center/.topnav-admin's own
   padding-top) rather than vertically centred, so a longer sentence that
   wraps to two lines grows downward from a fixed top edge instead of
   drifting upward past the nav. */
.orient-line{position:fixed;top:15px;left:20px;z-index:21;display:flex;align-items:center;gap:14px;width:fit-content;max-width:calc(50% - 220px);padding:3px 7px;flex-wrap:wrap;background:var(--accent);backdrop-filter:blur(30px) saturate(1.4);-webkit-backdrop-filter:blur(30px) saturate(1.4);border:0.5px solid rgba(0,0,0,0.12);border-radius:5px;}
.orient-text{font-family:"Project X",sans-serif;font-size:13px;color:rgba(0,0,0,0.65);line-height:1.4;}
/* Two clauses, two weights — the recap (context: "since X, we did Y") stays
   quiet; the live sentence (the one thing to actually act on) reads heavier
   and full-strength black, so the eye lands on what matters first. */
.orient-recap{font-weight:400;color:rgba(0,0,0,0.5);}
.orient-main{display:block;font-weight:700;color:#000;}
.orient-ack{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.3px;text-transform:uppercase;color:#3b4a2e;background:var(--accent);border-radius:5px;padding:4px 10px;white-space:nowrap;}
.orient-action{display:inline-flex;align-items:center;height:var(--lozenge-h);font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:#fff;background:#000;border:none;border-radius:6px;padding:0 16px;cursor:pointer;transition:background .2s;white-space:nowrap;}
.orient-action:hover{background:#222;}

/* DELIVERY GROUPING — locked vs available */
.dmod-group-label{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.3);padding:20px 0 8px;}

/* DELIVERY */
.dmod-wrap{background:#fff;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;overflow:hidden;}
.dmod{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 18px;flex-wrap:wrap;}
.dmod-left{display:flex;align-items:center;gap:14px;min-width:0;}
.dmod-date{font-family:"Project X",sans-serif;font-size:9px;letter-spacing:0.3px;text-transform:uppercase;color:rgba(0,0,0,0.25);}
.dmod-right{display:flex;align-items:center;gap:8px;flex-shrink:0;}
.dmod-icon{color:rgba(0,0,0,0.18);}
/* Delivery status lozenge — orange for pending, grey for paid */
.dmod-status{display:inline-flex;align-items:center;height:var(--lozenge-h);font-family:"Project X",sans-serif;font-weight:500;font-size:8px;letter-spacing:0.4px;text-transform:uppercase;padding:0.5px 10px 0;border-radius:5px;}
.dmod-status-pending{background:#F97316;color:#fff;}
.dmod-status-paid{background:#0000000f;color:rgba(0,0,0,0.5);}
.dbtn{display:inline-flex;align-items:center;gap:2px;height:var(--lozenge-h);font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;padding:0 18px;background:rgba(0,0,0,0.06);color:rgba(0,0,0,0.3);border:none;border-radius:5px;text-decoration:none;transition:background .2s;cursor:pointer;}
.dbtn-set{background:#000;color:#fff;}
.dbtn-set:hover{opacity:.85;}
.dbtn-add{background:rgb(228,230,227);color:rgba(0,0,0,0.5);border:none;}
.dbtn-add:hover{color:#000;background:rgb(200,203,197);}
.dbtn-edit{background:transparent;color:rgba(0,0,0,0.3);border:none;padding:9px 8px;font-size:12px;}
.dbtn-edit:hover{color:#000;}
.dmod-section-label{font-family:"Project X",sans-serif;font-weight:500;font-size:8px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.3);padding:12px 18px 4px;}
.dmod-finals-label{border-top:0.5px solid rgba(0,0,0,0.08);}
.dmod-task-row{display:flex;align-items:center;gap:12px;padding:0 18px 12px;}
.dmod-files{display:flex;flex-direction:column;}
.dmod-file-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:6px 18px;}
.dmod-file-name{font-family:"Project X",sans-serif;font-weight:500;font-size:12px;color:rgba(0,0,0,0.55);}
.dmod-file-date{font-family:"Project X",sans-serif;font-size:9px;letter-spacing:0.3px;text-transform:uppercase;color:rgba(0,0,0,0.25);}
/* Tool meta — version/access/docs/support, shown once a Tool deliverable is
   actually open-able (not for plain file drops, which have nothing to "use"). */
.dmod-tool-meta{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:10px 18px;border-top:0.5px solid rgba(0,0,0,0.08);}
.dmod-tool-meta-left{display:flex;align-items:center;gap:10px;min-width:0;}
.dmod-tool-meta-right{display:flex;align-items:center;gap:8px;flex-shrink:0;}
.dmod-version{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.3px;text-transform:uppercase;color:rgba(0,0,0,0.35);}
.dmod-access-note{font-family:"Project X",sans-serif;font-weight:400;font-size:12px;color:rgba(0,0,0,0.55);}
.dmod-meta-edit{background:transparent;color:rgba(0,0,0,0.3);border:0.5px dashed rgba(0,0,0,0.2);padding:5px 10px;font-size:10px;text-transform:none;letter-spacing:0;}
.dmod-meta-edit:hover{color:#000;border-color:rgba(0,0,0,0.4);}
.dmod-report-issue{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.3px;color:rgba(0,0,0,0.35);text-decoration:underline;text-underline-offset:2px;}
.dmod-report-issue:hover{color:#000;}

/* DRAFT BAND — an unsigned nda/sow document's own status, stated plainly. A
   bordered black-on-neutral box, not a red/amber warning fill — same
   "neutral, not alarmed" convention moduleIsOverdue() already documents
   (this is a fact about the document, not a problem with it). Must survive
   into print (see @media print) since a downloaded draft leaves the browser
   and may be read by someone who never saw the live page at all. */
.doc-draft-band{margin:var(--space-6) 46px 0;padding:14px 20px;border:1px solid #000;border-radius:8px;font-family:"Project X",sans-serif;font-weight:700;font-size:11px;letter-spacing:0.4px;text-transform:uppercase;color:#000;}

/* NDA INTRO — pre-proposal gate header, sits above the reused legal grid */
.nda-intro{margin:var(--space-6) 46px 0;max-width:640px;}
.nda-intro-label{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.25);margin-bottom:12px;}
.nda-intro-text{font-family:"Project X",sans-serif;font-weight:500;font-size:15px;line-height:1.4;letter-spacing:0.01em;color:#000;}
.page-nda .legal-master{margin-top:24px;}

/* A document's own controls inside the Edit bar's panel (?doc=<id> and
   ?record=… — see standaloneDocControls / recordEditPanel in app.js). Reuses
   the OS's own panel/button language (os-panel, col-label, os-ctrl-row,
   os-linkbtn) since it's the same admin control surface, just addressed at
   its own link. Zero margin: inside .os-tool-pop the popover already pads. */
.doc-admin-controls{margin:0;border:none;padding:0;background:transparent;}
.doc-admin-controls .os-row-meta{margin-top:6px;}

/* SCOPE COMMERCIAL TERMS — the fee/schedule/duration stated as figures, above
   the clause grid's prose. Same bordered-box language as .legal-master right
   below it (they read as one document), sized down since it's a handful of
   label/value rows, not a two-column grid of clause bodies. */
.scope-terms{margin:var(--space-6) 46px 0;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:20px 24px;display:flex;flex-direction:column;gap:10px;}
.scope-terms-row{display:flex;justify-content:space-between;align-items:baseline;gap:16px;}
.scope-terms-label{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.5);}
.scope-terms-value{font-family:"Project X",sans-serif;font-weight:700;font-size:14px;color:#000;}

/* LEGAL */
.legal-master{margin:var(--space-6) 46px 0;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:24px;}
.legal-master-label{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.25);margin-bottom:20px;}
.legal-grid{display:grid;grid-template-columns:1fr 1fr;gap:20px;}
.legal-clause-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;}
.legal-h{font-family:"Project X",sans-serif;font-size:11px;font-weight:700;letter-spacing:0.3px;text-transform:uppercase;color:#000;margin-bottom:0;}
.legal-b{font-family:"Project X",sans-serif;font-size:11px;font-weight:500;line-height:1.2;letter-spacing:0.04em;color:rgba(0,0,0,0.5);}
.legal-clause-toggle{flex:0 0 auto;font-family:"Project X",sans-serif;font-weight:500;font-size:8px;letter-spacing:0.4px;text-transform:uppercase;color:#000;background:rgb(228,230,227);border:none;border-radius:4px;height:18px;padding:0 8px;cursor:pointer;transition:background .15s;}
.legal-clause-toggle:hover{background:rgb(200,203,197);}
.legal-clause-excluded .legal-h,.legal-clause-excluded .legal-b{opacity:0.35;}

/* ── FIELD TO BE FILLED — the one canonical entry, used everywhere a user has to
   type something (signer name/role/email, party entity/address, OS forms). ALWAYS
   identical so a blank always reads the same. A rounded LOZENGE: empty = the loud
   "fill me in" state — a SOLID accent-green fill (full --accent, not the old faded
   16% that vanished into the page) + a defined border + 5px lozenge roundness, so a
   blank reads unmistakably as a green input waiting for you. Focus deepens the border
   to black; filled recedes to a neutral grey box so completed fields quiet down and
   only the green blanks stand out. Distinct from solid-fill (=clickable) and
   thin-outline boxes (=informational) — the third state forms need. */
.entity-input{font-family:"Project X",sans-serif;font-weight:500;font-size:13px;color:#000;background:transparent;border:1px solid #000;border-radius:5px;padding:10px 14px;outline:none;width:100%;transition:border-color .2s;}
.entity-input::placeholder{color:rgba(0,0,0,0.4);}
/* Empty = to-fill: accent-green outline (vs the black outline of a set field). As you
   fill it and it re-renders without .empty, the border goes black — the field "sets",
   matching MATA's already-set column opposite it. */
.entity-input.empty{border-color:var(--accent);background:#f6ffeb4f;}
.entity-input:focus,.entity-input.empty:focus{border-color:#000;}
.entity-input:focus::placeholder{color:transparent;}
/* Set/completed value — the same outline lozenge as a filled input, so the two columns
   mirror row-for-row: black outline, black text, no fill. Used for MATA's fixed identity
   and a party's own values once signed. */
.entity-fixed{font-family:"Project X",sans-serif;font-weight:500;font-size:13px;color:#000;border:1px solid #00000040;border-radius:5px;padding:10px 14px;}

/* SIGN FIELDS — the party's full identity is captured HERE, in one stack: entity +
   address + signatory name/role/email, then the Sign button. (Merged from the old
   separate "entity details" block up top — a signature block carries party identity
   in one place, which is both tidier and the standard contract convention.) */
.sign-fields{margin-top:14px;display:flex;flex-direction:column;gap:14px;}
.doc-sent{margin-top:16px;font-family:"Project X",sans-serif;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.4);}

/* FINAL SIGNATURE — two columns: the party fills the left, MATA's right column is the
   same identity already inked in (entity/address/name/role), so the page shows what
   "done" looks like and the party's side visually converges on it as they type. */
.final-sign{margin:16px 46px 0;border:0.5px solid #000;border-radius:10px;padding:24px;}
.final-sign-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px;}
/* Static identity stack — MATA's fixed side, and the party's own values once signed.
   Same 14px gap as .sign-fields so the two columns line up lozenge-for-lozenge. */
.sign-idblock{margin-top:14px;margin-bottom:16px;display:flex;flex-direction:column;gap:14px;}

/* NOTES */
.notes{margin:var(--space-6) 46px 0;padding-left:20px;}
.notes-text{font-family:"Project X",sans-serif;font-size:12px;font-weight:500;line-height:1.2;letter-spacing:0.04em;color:rgba(0,0,0,0.5);column-count:2;column-gap:40px;}

/* FOOTER */
.footer{padding:40px 46px 20px;}
/* Page-level action buttons — shared convention throughout the OS.
   Group related actions together in .page-actions; each is an .action-btn. */
.page-actions{display:flex;justify-content:center;align-items:center;gap:8px;padding:160px 46px 0;}
.page-delivery .page-actions{flex:1;padding:24px 46px;}
.action-btn{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;background:rgb(228,230,227);color:#000;border:none;border-radius:5px;padding:13px 32px;cursor:pointer;transition:background .2s;}
.action-btn:hover{background:rgb(200,203,197);}

/* Legacy — still used for standalone doc send and signing pages */
.pdf-btn-wrap{display:flex;justify-content:center;gap:8px;padding:160px 46px 0;}
.page-delivery .pdf-btn-wrap{flex:1;align-items:center;padding:24px 46px;}
.footer-url{padding:32px 46px 40px;display:flex;}
.pdf-btn{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;background:rgba(0,0,0,0.08);color:#000;border:none;border-radius:5px;padding:13px 48px;cursor:pointer;transition:background .2s;}
.pdf-btn:hover{background:rgba(0,0,0,0.14);}
button.pill{border:none;cursor:pointer;}

/* MODULE LIBRARY */
.lib-backdrop{position:fixed;inset:0;z-index:55;background:rgba(240,242,239,0.92);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);overflow-y:auto;animation:fadeIn .25s ease both;}
.lib-panel{max-width:900px;margin:0 auto;padding:40px 46px 100px;}
.lib-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:32px;}
.lib-title{font-family:"Project X",sans-serif;font-weight:200;font-size:40px;color:#000;}
.lib-modules{display:flex;flex-direction:column;gap:10px;}
.lib-addbtn{font-family:"Project X",sans-serif;font-weight:500;font-size:16px;width:var(--lozenge-h);height:var(--lozenge-h);border:none;border-radius:5px;background:rgb(228,230,227);color:#000;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .2s,color .2s;flex-shrink:0;}
.lib-addbtn:hover{background:#000;color:#fff;}
.lib-added{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.25);}

/* FIXED MATA LOZENGE — bottom right, client-facing pages */
.mata-lozenge-fixed{position:fixed;bottom:20px;left:24px;z-index:40;}
.mata-lozenge-fixed .pill{background:rgba(240,242,239,.85);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);text-decoration:none;}
/* Proposal slide counter — opposite mata.systems, bottom-right, OS lozenge style */
.proposal-pagenum-fixed{position:fixed;bottom:20px;right:24px;z-index:40;}
.proposal-pagenum-fixed .pill{background:rgba(240,242,239,.85);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);font-variant-numeric:tabular-nums;}
/* Swipe-up hint — bottom-centre, between the two corner pills; proposal deck
   only, and only while slide 1 (the intro) is current — initProposalPager's
   same IntersectionObserver that drives the counter toggles .is-hidden the
   instant the visitor swipes past it, and brings it back if they scroll back
   up (app.js). Three chevrons chase upward on a stagger (a third of the
   cycle apart, not half) — each one independently sweeps from --sh-amp below
   centre to the mirrored height above, fading in/out at the ends of its own
   run, rather than wiggling in a fixed spot; three closes the gap between
   them without touching any one sweep's own length. --sh-amp is redefined
   smaller at the mobile breakpoint below so the sweep still clears the
   shorter pill. Flat wide chevron (2x the old width, same height), rendered
   at 80% of its earlier box size — one shape shared by all three paths.
   Sharp linecap/linejoin (butt/miter) and a 0.5 stroke — deliberately not
   the soft round ends/default weight the rest
   of the icon set uses (BTN_ICONS); this one reads as a caret. */
.prop-swipehint-fixed{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);z-index:40;transition:opacity .2s ease,transform .2s ease;--sh-amp:7px;}
.prop-swipehint-fixed.is-hidden{opacity:0;transform:translateX(-50%) translateY(6px);}
.prop-swipehint-fixed .pill{width:calc(var(--lozenge-h) * 2);padding:0;background:rgba(240,242,239,.85);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);color:rgba(0,0,0,0.55);}
.swipehint-chevron{width:17.28px;height:17.28px;overflow:visible;}
.swipehint-chevron path{opacity:0;animation:swipehintChase 3s ease-in-out infinite;}
.swipehint-chevron .sh-c2{animation-delay:1s;}
.swipehint-chevron .sh-c3{animation-delay:2s;}
@keyframes swipehintChase{
  0%{opacity:0;transform:translateY(var(--sh-amp));}
  20%,65%{opacity:1;}
  100%{opacity:0;transform:translateY(calc(-1 * var(--sh-amp)));}
}
@media (prefers-reduced-motion:reduce){
  .swipehint-chevron path{animation:none!important;}
}
/* Express lane — the decided buyer's fast path: just the one action, pinned
   bottom-centre between the two corner pills, frosted to match them. Scope
   facts (modules/duration/price) now live as a static overview under the
   modules themselves (.prop-scope-overview) instead of pinned here. */
/* .prop-express is now only ever the STATIC overview under the scope modules
   (proposalScopeOverview) — never a viewport-pinned bar. The CTA it used to
   carry moved in-flow onto the back cover (see backCover/proposalScopeAction). */
.prop-express{display:flex;align-items:center;gap:14px;padding:7px 7px 7px 16px;background:rgba(240,242,239,.85);border:0.5px solid rgba(0,0,0,0.1);border-radius:9px;max-width:100%;}
.prop-express-facts{display:flex;align-items:center;font-family:"Project X",sans-serif;font-size:10px;font-weight:500;letter-spacing:0.4px;text-transform:uppercase;color:#000;white-space:nowrap;overflow:hidden;}
.prop-express-fact{padding:0 12px;position:relative;}
.prop-express-fact:first-child{padding-left:0;}
.prop-express-fact + .prop-express-fact::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);width:1px;height:9px;background:rgba(0,0,0,0.18);}
/* Styled to match .back-cover-iconbtn (its only home now — see backCover) —
   same grey fill/hover as the Download button beside it, not the black CTA
   this used to be as a pinned bar's one action. */
.prop-express-cta{display:inline-flex;align-items:center;height:44px;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:#000;background:rgba(0,0,0,0.08);border:none;border-radius:6px;padding:0 20px;cursor:pointer;transition:background .2s;white-space:nowrap;}
.prop-express-cta:hover{background:rgba(0,0,0,0.14);}
/* Same box as .prop-express-cta right above (height, padding, type) — only
   the state itself (colour, text, tick) should ever differ between "ask"
   and "requested", never the sizing. */
.prop-express-done{display:inline-flex;align-items:center;height:44px;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:#3b4a2e;background:var(--accent);border-radius:6px;padding:0 20px;white-space:nowrap;}
/* Scope overview — the same facts row, in-flow under the modules on the
   proposal's own scope page instead of pinned; a small, quiet summary, not
   a second CTA (the express bar already owns the one button). */
.prop-scope-overview{display:flex;justify-content:center;margin-top:32px;}

/* SIGN MODAL */
.modal-backdrop{position:fixed;inset:0;z-index:60;background:rgba(240,242,239,.6);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;animation:fadeIn .25s ease both;}
@keyframes fadeIn{from{opacity:0;}to{opacity:1;}}
.modal{position:relative;width:380px;max-width:calc(100vw - 40px);background:rgba(255,255,255,.45);backdrop-filter:blur(30px) saturate(1.4);-webkit-backdrop-filter:blur(30px) saturate(1.4);border:0.5px solid rgba(255,255,255,0.5);border-radius:14px;padding:28px;box-shadow:0 20px 60px rgba(0,0,0,.12);animation:modalIn .3s cubic-bezier(.16,1,.3,1) both;}
@keyframes modalIn{from{opacity:0;transform:translateY(10px) scale(.98);}to{opacity:1;transform:none;}}
.modal-close{position:absolute;top:18px;right:18px;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border:none;background:transparent;border-radius:6px;cursor:pointer;transition:background .2s;}
.modal-close:hover{background:rgba(0,0,0,0.06);}
.modal-title{font-family:"Project X",sans-serif;font-size:20px;font-weight:500;letter-spacing:-0.02em;color:#000;}
.modal-sub{font-family:"Project X",sans-serif;font-weight:500;font-size:11px;letter-spacing:0.04em;color:rgba(0,0,0,0.45);margin-top:6px;margin-bottom:20px;}
/* Tier 3 ack dialog (taskAckModal, app.js) — the thing being acknowledged, same
   weight as a filled .modal-input but non-interactive (it's a receipt, not a form). */
.modal-ack-artefact{font-family:"Project X",sans-serif;font-weight:500;font-size:13px;color:#000;background:rgba(0,0,0,0.04);border:0.5px solid rgba(0,0,0,0.12);border-radius:8px;padding:12px 14px;margin-bottom:20px;}
.modal-fields{display:flex;flex-direction:column;gap:10px;}
.modal-input{font-family:"Project X",sans-serif;font-weight:500;font-size:13px;letter-spacing:0.02em;color:#000;background:rgba(0,0,0,0.04);border:0.5px solid rgba(0,0,0,0.12);border-radius:8px;padding:12px 14px;outline:none;width:100%;}
.modal-input:focus{border-color:rgba(0,0,0,0.4);}
.modal-siglabel{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.25);}
.modal-sigrow{display:flex;align-items:center;justify-content:space-between;margin-top:8px;}
.modal-sigpad{display:block;width:100%;height:120px;border:0.5px solid rgba(0,0,0,0.2);border-radius:8px;background:rgba(0,0,0,0.02);cursor:crosshair;touch-action:none;margin-top:6px;}
/* Upload trigger reads as the same understated tone as the Signature label beside
   it — a label wrapping a hidden file input, no separate button chrome needed. */
.modal-sigupload{font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.3px;color:rgba(0,0,0,0.4);cursor:pointer;transition:color .15s;}
.modal-sigupload:hover{color:#000;}
.modal-sigclear{display:block;margin:6px 0 0 auto;background:none;border:none;padding:0;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.3px;color:rgba(0,0,0,0.35);cursor:pointer;}
.modal-sigclear:hover{color:#000;}
.sign-sig-img{display:block;width:100%;height:60px;object-fit:contain;object-position:left center;margin-top:8px;margin-bottom:-4px;opacity:0.75;}
/* "Using your saved signature" — sits between the fillable fields and the Sign
   button so the button is never a surprise once someone has a mark on file. */
.sign-preview{display:flex;align-items:center;gap:8px;background:rgba(0,0,0,0.03);border:0.5px solid rgba(0,0,0,0.08);border-radius:8px;padding:8px 10px;margin-top:2px;}
.sign-preview-img{width:44px;height:24px;object-fit:contain;object-position:left center;flex-shrink:0;}
.sign-preview-label{flex:1;font-family:"Project X",sans-serif;font-weight:500;font-size:10.5px;color:rgba(0,0,0,0.45);}
.sign-preview-replace{background:none;border:none;padding:0;font-family:"Project X",sans-serif;font-weight:500;font-size:10.5px;letter-spacing:0.2px;color:rgba(0,0,0,0.55);text-decoration:underline;cursor:pointer;flex-shrink:0;}
.sign-preview-replace:hover{color:#000;}
/* Who is signing — stated in the dialog, since with the name fields gone the
   signatory is resolved rather than typed, and a signer should always be able to
   see which identity is about to go on the record. */
.modal-signer{font-family:"Project X",sans-serif;font-weight:500;font-size:11px;letter-spacing:0.2px;color:rgba(0,0,0,0.45);margin-top:10px;}
/* Same warning pair as .os-entry-person.is-missing / .os-entry-data-item.is-missing —
   one "something needs attention" colour across the app, not a new red for this. */
.modal-error{font-family:"Project X",sans-serif;font-weight:500;font-size:12px;line-height:1.4;color:#ff7070;background:#ffe1d7;border-radius:6px;padding:10px 12px;margin-top:14px;}
.modal-actions{display:flex;gap:8px;margin-top:22px;}
/* The Deed's confirm is the same press-and-hold as a Tier 2 gate's — the tiers
   differ in what they RECORD, never in how committing feels. Sized to the dialog's
   own button footprint rather than the band's. */
.modal-actions .tl-holdbtn{padding:14px;font-size:11px;letter-spacing:0.5px;border-radius:8px;background:#000;color:#fff;}
.modal-actions .tl-holdbtn .tl-holdbtn-fill{background:rgba(255,255,255,0.28);}
.modal-btn{flex:1;font-family:"Project X",sans-serif;font-weight:500;font-size:11px;letter-spacing:0.5px;text-transform:uppercase;padding:14px;border:none;border-radius:8px;cursor:pointer;}
.modal-btn.solid{background:#000;color:#fff;}

/* MOBILE — client links open from email on phones. Nothing that carries
   meaning is hidden here; it is restyled to fit. */
@media (max-width:600px){
  /* ── MOBILE PAN — the primitive both the timeline split and the OS row-group
     split are built from (see panRegister()/panSet()/panPills(), app.js). One
     custom property per surface (--pan-i, written on the surface root) drives
     EVERY .pan-group inside it at once — that single write is what guarantees
     lockstep, never a per-row transform and never a scroll container. Above this
     breakpoint .pan-group carries no transform at all, so desktop is untouched. */
  .pan-track{position:relative;overflow:hidden;touch-action:pan-y;}
  .pan-group{transform:translateX(calc(var(--pan-i,0) * -100%));transition:transform .28s cubic-bezier(.22,.61,.36,1);will-change:transform;}
  .pan-pills{display:flex;gap:2px;justify-content:center;}
  /* .pan-pill is lozenge family — see the --lozenge-h comment in :root. */
  .pan-pill{display:inline-flex;align-items:center;justify-content:center;height:var(--lozenge-h);padding:0 16px;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.4);background:rgb(228,230,227);border:none;border-radius:5px;cursor:pointer;}
  .pan-pill.is-active{color:#fff;background:#000;}
  @media (prefers-reduced-motion:reduce){
    .pan-group{transition:none;}
  }
  /* Any element that counter-transforms against .pan-group (currently just the
     timeline's module header, below) must animate on the EXACT SAME schedule —
     same duration, same easing — or the two fall out of sync for the length of
     the transition and the "fixed" element visibly jumps then settles back
     instead of staying still throughout. */
  .pan-counter{transition:transform .28s cubic-bezier(.22,.61,.36,1);}
  @media (prefers-reduced-motion:reduce){
    .pan-counter{transition:none;}
  }

  /* Admin bar, narrow — the resting row stays the same 28px strip
     (html.admin-chrome's own offset rules assume that exact height; keep it
     single-line, never let it wrap to two) whether or not this is the
     project surface's --expand variant (admin-bar-fixed--expand's own height
     is auto, but .admin-bar-row inside it is still exactly this 28px).
     The label shrinks and ellipsizes first — a long client name plus the
     "(editing is a desktop surface)" note will not both fit at 375px, and
     that's fine, the note is a courtesy, not the point. Targets both
     shapes: doc/record's label/trigger/dirty are direct children of
     .admin-bar-fixed--narrow itself; the project surface's are one level
     deeper, inside .admin-bar-row. */
  .admin-bar-fixed--narrow,.admin-bar-fixed--narrow .admin-bar-row{gap:8px;}
  .admin-bar-fixed--narrow .admin-bar-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  .admin-bar-desktop-note{opacity:0.6;}

  /* Top nav — the stage strip collapses to one trigger + sheet (below); the
     date drops into its own slim row. */
  .topnav{display:flex;flex-direction:column;align-items:center;padding:0 12px;}
  .topnav-admin{padding-top:10px;}
  .topnav-center{padding:10px 0 0;max-width:100%;}
  /* Still used unconditionally (not gated on isNarrow()) by the standalone
     document page and the Vault record editor, each a single non-interactive
     "active" tab — .nav-collapse-wrap below is topNav()'s own replacement for
     ITS multi-stage strip specifically, not a wholesale replacement of this
     class everywhere it appears. */
  .topnav-track{overflow-x:auto;max-width:calc(100vw - 24px);scrollbar-width:none;}
  .topnav-track::-webkit-scrollbar{display:none;}
  .topnav-right{order:3;padding-top:0;}
  /* Files trigger doesn't stack into the column flow like the rest of
     .topnav-right (the date chip) — it stays pinned top-right, same corner-chrome
     pattern as .mata-lozenge-fixed/.proposal-pagenum-fixed elsewhere on mobile. */
  .record-menu-wrap{position:fixed;top:10px;right:12px;z-index:25;}
  /* .files-trigger's -31px right margin exists to pull it tight against a
     desktop sibling in the .topnav-right flex row. Pulled out to position:fixed
     on mobile, that same negative margin has nothing to compensate against any
     more and just bleeds the trigger 31px past the wrap's own right edge,
     off the viewport — cancel it here. */
  .record-menu-wrap .files-trigger{margin-right:0;}
  /* The date used to drop into its own slim row here (see the collapsed nav
     comment above) — sticky, it then stayed on screen as its own row,
     overlapping whatever content had scrolled up underneath it. Not
     essential chrome on mobile — drop it rather than have it float there. */
  .topnav-date{display:none;}
  /* ── Collapsed stage nav ──
     One trigger (current stage + chevron) stands in for the whole strip; a tap
     reveals every visible stage as a sheet. Same click-toggle/outside-click/
     Escape-close shape as the Vault trigger beside it (recordMenuOpen) and the
     OS's own Today trigger (osTodayOpen, os.js) — not a new interaction to learn. */
  .nav-collapse-wrap{position:relative;}
  /* Grey/black-text, same as the OS lozenge family's own resting look
     (.topnav-item/.os-nav-item unpressed) — not black/white. This trigger
     just opens the stage sheet below; it isn't itself a "selected" pill the
     way an active tab is, so it shouldn't read as one. */
  .nav-collapse-trigger{display:inline-flex;align-items:center;gap:6px;height:var(--lozenge-h);padding:0 16px;font-family:"Project X",sans-serif;font-weight:500;font-size:11px;letter-spacing:0.5px;text-transform:uppercase;color:#000;background:rgb(232,232,232);border:none;border-radius:5px;cursor:pointer;}
  .nav-chevron{flex-shrink:0;}
  .nav-sheet{position:absolute;top:100%;left:50%;transform:translateX(-50%);margin-top:8px;min-width:160px;display:flex;flex-direction:column;gap:2px;background:#fff;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:6px;z-index:45;box-shadow:0 10px 34px rgba(0,0,0,0.12);}
  .nav-sheet-item{display:flex;align-items:center;height:36px;padding:0 12px;font-family:"Project X",sans-serif;font-weight:500;font-size:12px;letter-spacing:0.2px;color:rgba(0,0,0,0.55);background:transparent;border:none;border-radius:6px;cursor:pointer;text-align:left;}
  .nav-sheet-item:hover{background:rgba(0,0,0,0.05);}
  .nav-sheet-item.is-active{color:#000;background:rgba(0,0,0,0.06);font-weight:700;}
  /* Type ramp — display faces step down, labels/body hold */
  .header{padding:16px 20px;}
  .hero{padding:32px 20px 24px;flex-direction:column;align-items:flex-start;gap:8px;}
  .hero-center{padding:48px 20px;}
  .hero-compact{margin-top:48px;}
  .page-proposal .hero-compact{padding-top:36px;}
  .hero-title{font-size:34px;}
  .approach-text{font-size:29px;letter-spacing:-1px;}
  .quote-text{font-size:18px;}
  .back-cover-text{font-size:28px;}
  /* 1.73vmin sizes off whichever viewport dimension is smaller — on mobile
     portrait that's the (narrow) width rather than desktop's height, so the
     same value that reads fine on a desktop window comes out under 7px
     here. Doubled, not just bumped to a fixed px, so it still scales with
     the device the way the desktop rule intends. */
  .prop-intro-text{font-size:3.46vmin;}
  /* Page 4's black card is a deliberate full-bleed beat on mobile — the
     20px gutter every other slide keeps (kept here too, vertically) reads
     as wasted void around a colour block at this width, not restraint. */
  .page-proposal .prop-slide:has(.challenges-card){padding-left:0;padding-right:0;}
  .challenges-card{max-width:100%;border-radius:0;}
  /* Section rhythm — 200px breaths become 80px, side margins 46px become 20px */
  .approach{margin:0 20px 24px;padding:16px;}
  .approach-proposal{padding:40px 20px;}
  .approach-method{margin:40px 20px 48px;}
  .approach-pill-wrap{margin-bottom:40px;}
  .approach-cols{grid-template-columns:1fr;row-gap:32px;}
  .process-module .tl-module-body{padding:0 12px 24px;}
  .quote-gallery{padding:32px 20px 36px;}
  .page-proposal .approach,.page-proposal .approach-method,.page-proposal .modules-section{margin-top:80px;}
  .page-proposal .modules{gap:48px;}
  .needs-overview{gap:24px;}
  /* Modules — Scope/library cards stack meta; proposal cards go name-over-meta */
  .modules{margin:0 20px;gap:24px;}
  .module-top{padding:14px 16px;}
  .module-top-right{flex-direction:column;align-items:flex-end;gap:2px;}
  .module-body{grid-template-columns:1fr;}
  .module-col+.module-col{border-left:none;border-top:0.5px solid rgba(0,0,0,0.08);}
  .module-col{padding:16px;}
  .modules-section .module-top{height:auto;flex-direction:column;justify-content:center;gap:5px;padding:18px 44px;}
  .mod-prop-meta{position:static;transform:none;flex-direction:row;align-items:center;gap:8px;}
  .mod-remove{left:auto;right:8px;top:8px;transform:none;}
  /* Timeline — tighter chips, icon/toggle hug the card edges */
  .vt{padding:0 4px;}
  .tl-module .tl-row{padding:0 12px;}
  /* No max-width here any more — that was surviving the squeeze the mobile pan
     (below) removes. A row's own `1fr auto 1fr` grid (invariant 1, unchanged)
     now has a whole party-column's width to give the label, not a fraction of
     the full row split three ways; see initTlMobilePan()/`.vt .pan-group`. */
  .tl-chip-label{font-size:10.93px;padding:0 8px;}
  .tl-mod-icon{left:12px;}
  .tl-toggle{right:12px;}
  /* ── Timeline mobile pan — MATA | Client ──
     initTlMobilePan() (app.js) sets --tl-pan-shift (one party column's width, in
     px) and .pan-group's own width (2·column + the 70px date chip) once per
     render, measured against the real rendered track width. This rule overrides
     the generic `-100%`-per-panel .pan-group transform above with that exact
     pixel shift — moving by a whole WINDOW would push the date chip off-screen;
     moving by one COLUMN is what keeps it glued to the rail at both panel
     positions, visible the entire time, never leaving invariant 1. */
  .vt .pan-group{position:relative;transform:translateX(calc(var(--pan-i,0) * -1 * var(--tl-pan-shift,0px)));}
  /* .vt-rail nests inside .pan-group here (see timeline()) so it pans in
     lockstep with the date chips — its `left:50%` now resolves against
     .pan-group's WIDE content width (thanks to position:relative above), which
     lands it on exactly the same column every row's own grid already centres
     its date on. initTlRailBounds() finds it via a plain descendant query
     regardless of this extra nesting level. */
  /* The gate band has no date chip of its own to act as a spine, so its two
     parties just split the same colW rhythm the rows use, with a 70px gap
     standing in for where a date chip would sit — landing MATA under the MATA
     column and Client under the Client column without needing its own pan. */
  .vt .tl-gate-parties{gap:70px;}
  .vt .tl-gate-party{flex:0 0 calc(var(--tl-pan-shift,50%) - 20px);}
  /* A module's own TITLE (icon/name/toggle) is neutral — same for both parties,
     not something the pan should ever reveal or hide. Left alone it would
     inherit the wide 664px card as its own width (a plain block child of
     .pan-group) and get physically dragged sideways by the SAME transform that
     correctly moves the party-specific rows below it — the exact bug this rule
     fixes: pin the header back to the real window width, then cancel the
     ambient drag with an EQUAL AND OPPOSITE transform, so the title renders at
     the same on-screen spot regardless of which panel is showing. */
  .vt .pan-group .tl-row.mod-head{width:var(--tl-window-w,100%);transform:translateX(calc(var(--pan-i,0) * var(--tl-pan-shift,0px)));}
  .vt .tl-titlerow{margin-bottom:32px;}
  .vt>.pan-pills{margin-bottom:24px;}
  /* Documents & signing */
  .legal-grid{grid-template-columns:1fr;}
  .final-sign-grid{grid-template-columns:1fr;}
  .legal-master,.final-sign,.notes,.nda-intro{margin-left:20px;margin-right:20px;}
  .notes-text{column-count:1;}
  /* Nav stacks into rows on mobile (see .topnav above) — no single lozenge
     row height to level with, so this drops fixed positioning and goes back
     to a normal-flow centred card underneath the (now taller) stacked nav. */
  .orient-line{position:static;transform:none;justify-content:center;margin:12px auto 40px;max-width:calc(100% - 40px);}
  /* Footers & actions */
  .footer{padding:32px 20px 20px;}
  .footer-url{padding:32px 20px 40px;}
  .page-actions,.pdf-btn-wrap{padding:80px 20px 0;flex-wrap:wrap;}
  /* Fixed chrome — mata.systems bottom-left, slide counter bottom-right.
     Same position:fixed as desktop (inherited unchanged from the base
     rule) — just smaller, tucked closer to the corner. */
  .mata-lozenge-fixed{left:12px;bottom:12px;}
  .proposal-pagenum-fixed{right:12px;bottom:12px;}
  .prop-swipehint-fixed{bottom:12px;--sh-amp:5px;}
  /* align-items:center centres the LINE BOX, not the glyphs within it — at
     this small a size the font's own metrics (descenders in "systems"/"y")
     sit visibly high inside that box unless nudged down a touch. Same fix
     already applied to .topnav-item for the same reason at a bigger size. */
  .mata-lozenge-fixed .pill,.proposal-pagenum-fixed .pill{padding:0.5px 9px 0;font-size:8px;height:18px;}
  /* Deliberately NOT shrunk to 18px like its two neighbours above — this one
     is pinned to the topnav tabs' own height (.topnav-item, var(--lozenge-h))
     instead, unchanged across breakpoints, so it still reads as a lozenge in
     that family even while its siblings shrink. */
  .prop-swipehint-fixed .pill{width:36px;height:var(--lozenge-h);}
  .swipehint-chevron{width:14.4px;height:14.4px;}
  .prop-express{max-width:100%;gap:8px;padding:6px 6px 6px 12px;}
  .prop-express-facts{font-size:9px;}
  .prop-express-cta,.prop-express-done{font-size:9px;padding:0 12px;}
}

/* ── MATA OS (admin cockpit, ?os) — top menu reuses the client .topnav ── */
/* margin:0 auto — the whole cockpit (content + menu) is meant to stay
   centred in the browser at any width; V=211 briefly changed this to
   margin:0 on a misreading of Tom's "these are centred in browser screen"
   as a complaint, when it was confirming the centering is correct. Reverted
   same day. */
.os{width:100%;margin:0 auto;padding:2px 46px 120px;}
/* +New is pinned to the viewport's top-right corner — fixed, not part of the
   topnav grid, so it stays put at the same 10px/10px offset regardless of
   scroll or which OS view is showing. Icon-only — the same "+" glyph as a
   module's collapsed toggle (TL_TOGGLE_ICON.closed), white on the black
   lozenge (the icon's stroke is currentColor, so setting color:#fff paints it). */
.os-topnav-new{display:inline-flex;align-items:center;justify-content:center;width:var(--lozenge-h);height:var(--lozenge-h);color:#fff;background:#000;border:none;border-radius:5px;padding:0;cursor:pointer;transition:background .2s;}
.os-topnav-new svg{display:block;}
.os-topnav-new:hover{background:#222;}
/* +New retains click/touch and reveals on hover/focus. The first 6px
   gap is padding, not margin, so crossing it keeps the pointer in the menu. */
.os-new-wrap{position:fixed;top:10px;right:10px;z-index:21;}
/* Anchored right:0 (not left:0) — the wrap now sits flush against the
   viewport's right edge, so the dropdown has to open leftward to stay
   on-screen instead of running off the right side. No card chrome here —
   just the lozenges themselves, floating with their own gap; the group has
   no enclosing background/border/shadow of its own. */
.os-new-stack{position:absolute;top:100%;right:0;display:none;flex-direction:column;align-items:flex-end;gap:6px;z-index:50;}
.os-new-stack{padding-top:6px;}
.os-new-wrap:hover .os-new-stack,.os-new-wrap:focus-within .os-new-stack,.os-new-stack.is-open{display:flex;}
/* Lozenge family (see :root comment) — a plain grey pill like .topnav-item. */
.os-new-item{display:flex;align-items:center;text-align:left;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.35);background:rgb(228,230,227);border:none;border-radius:5px;height:var(--lozenge-h);padding:0 14px;cursor:pointer;white-space:nowrap;transition:color .3s ease;}
.os-new-item:hover{color:rgba(0,0,0,0.6);}
/* Today — a fixed top-left corner trigger, the mirror of +New's top-right
   one (see .os-new-wrap). Click reveals it, rather than hover, since this
   one's read rather than acted on in passing. */
.os-today-wrap{position:fixed;top:10px;left:10px;z-index:21;}
.os-topnav-today{position:relative;display:inline-flex;align-items:center;justify-content:center;width:var(--lozenge-h);height:var(--lozenge-h);color:#fff;background:#000;border:none;border-radius:5px;padding:0;cursor:pointer;transition:background .2s;}
.os-topnav-today svg{display:block;}
.os-topnav-today:hover{background:#222;}
/* Count of items waiting — without it there's no reason to ever click the
   trigger, since (unlike +New) nothing here is visible until opened. */
.os-today-badge{position:absolute;top:-4px;right:-4px;min-width:14px;height:14px;padding:0 3px;border-radius:7px;background:#F59E0B;color:#fff;font-family:"Project X",sans-serif;font-weight:700;font-size:8px;line-height:14px;text-align:center;}
.os-today-pop{position:absolute;top:100%;left:0;margin-top:8px;width:380px;max-width:calc(100vw - 20px);max-height:70vh;overflow-y:auto;z-index:50;}
/* OS — Today digest: the pipeline is read, not checked. Soft mint fill so
   it's the calm "start here" panel, distinct from plain white content. Now
   only ever rendered inside .os-today-pop, so the shadow lives here rather
   than being conditional. */
.os-today{background:#F6FFEB;border-radius:10px;padding:18px 20px 12px;box-shadow:0 10px 34px rgba(0,0,0,0.12);}
.os-today .os-ov-label{color:rgba(0,0,0,0.4);}
.os-today-rows{display:flex;flex-direction:column;margin-top:8px;}
.os-today-row{display:flex;align-items:center;gap:10px;padding:8px 0;}
/* Every door-row (project, invoice, docs, prospects) gets the same pointer +
   hover — previously only [data-osproject] rows looked clickable, so the
   money/prospect rows (which ARE clickable, just to a different surface)
   gave no visual hint at all that clicking did anything. */
.os-today-row-link{cursor:pointer;}
.os-today-row-link:hover .os-today-text{opacity:.55;}
.os-today-row+.os-today-row{border-top:0.5px solid rgba(0,0,0,0.1);}
.os-today-dot{width:6px;height:6px;border-radius:3px;flex-shrink:0;}
.os-today-dot.t-client{background:#F59E0B;}
.os-today-dot.t-mata{background:#000;}
.os-today .client-pill{border-color:rgba(0,0,0,0.3);color:rgba(0,0,0,0.65);}
/* Scope requested/signed — the two moments worth a second look — get more
   visual weight than routine digest lines: a bigger dot, bolder text, a
   highlight band bleeding to the panel edges. */
.os-today-row.os-today-important{margin:0 -20px;padding:8px 20px;background:rgba(0,0,0,0.05);border-radius:6px;border-top:none;}
.os-today-important+.os-today-row{border-top:none;}
.os-today-important .os-today-dot{width:9px;height:9px;}
.os-today-important .os-today-text{font-weight:700;}
.os-today-dot.t-event{background:rgba(0,0,0,0.2);}
.os-today-text{font-family:"Project X",sans-serif;font-weight:500;font-size:12.5px;color:#000;transition:opacity .15s;}
.os-today-when{margin-left:auto;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.5);white-space:nowrap;}
/* Names where a click lands, for the rows that don't go to a project workspace. */
.os-today-dest{margin-left:auto;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.3);white-space:nowrap;}
.os-today-dest+.os-today-when{margin-left:8px;}
.os-today-empty{font-family:"Project X",sans-serif;font-weight:500;font-size:12.5px;color:rgba(0,0,0,0.5);}
.os-ov-label{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.35);}
.os-metric-label{font-family:"Project X",sans-serif;font-weight:500;font-size:8px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.4);}
/* ══ ENTRY ROW — the one module shape across Projects / Persons / Vault ══
   Figma MATA_OS 3450:9544 / 3452:10344 / 3452:10784. Seven fixed columns
   totalling 900px, identical in all three views (see osEntryRow in os.js).
   Cells sit FLUSH — no gap — and each carries its own 6px radius, so where two
   meet the curves leave the small optical notch the design shows. Every cell is
   vertically centred and sizes to its own content; only NAME sets the row
   height (90px primary / 41px child), which is what makes the columns line up
   across rows of different heights. */
/* DATA's old 2fr split into DATA + DATES, exactly half each (1fr + 1fr) — same
   total width as before, now two columns instead of one. */
.os-entry{display:grid;grid-template-columns:1fr 4fr 2fr 1fr 1fr 1fr 1fr 1fr;align-items:center;width:calc(100% - 40px);min-width:640px;margin:0 auto;}
/* Every grid item defaults to min-width:auto, which lets its intrinsic content
   size (a long project name, a long email) push past its own track instead of
   ellipsizing inside it — min-width:0 here is what makes the fixed 900px grid
   actually fixed regardless of content length. */
.os-entry>*{min-width:0;}
.os-entry-cell{background:#eae8e8;border-radius:6px;box-sizing:border-box;font-family:"Project X",sans-serif;color:#000;text-align:left;border:none;}
/* Tone = state for the whole row. Live green and attention pink are the
   designed fills (#edffd7 / #ffe1d7), not the client portal's own --accent —
   this is the OS's own palette. */
.os-entry--live .os-entry-cell,.os-entry--live .os-entry-person,.os-entry--live .os-entry-data-item{background:#edffd7;}
.os-entry--attention .os-entry-cell,.os-entry--attention .os-entry-person,.os-entry--attention .os-entry-data-item{background:#ffe1d7;}
.os-entry-cat{display:flex;align-items:center;padding:7.5px 10px;font-weight:700;font-size:10px;letter-spacing:0.4px;text-transform:uppercase;white-space:nowrap;overflow:hidden;}
/* line-height:1.1 — a wrapping title (a long link summary, a long project
   name) sat far too open at the browser default ~1.4 for 25px type. */
.os-entry-name{display:flex;align-items:center;min-height:90px;padding:37.5px 10px;font-weight:200;font-size:25px;line-height:1.1;letter-spacing:-0.25px;overflow-wrap:break-word;white-space:normal;}
.os-entry--child .os-entry-name{min-height:41px;padding:12.5px 10px;font-size:17.5px;line-height:1.1;letter-spacing:0.14px;justify-content:flex-start;text-align:left;}
/* Presentation only — see osEntryRow's cfg.nameClass (js/os.js). The
   EDITING input never carries these, so the raw stored casing always shows
   (and round-trips unchanged) the moment Edit is opened. */
.os-entry-name--company{text-transform:uppercase;}
.os-entry-name--person{text-transform:capitalize;}
/* PERSONS is a stack of its own lozenges (1–2), not one cell — the container
   itself is unfilled, which is why each person carries the tone fill above. */
.os-entry-persons{display:flex;flex-direction:column;justify-content:center;}
.os-entry-person{display:flex;align-items:center;min-height:29px;padding:12.5px 10px;background:#eae8e8;border-radius:6px;box-sizing:border-box;font-family:"Project X",sans-serif;font-weight:700;font-size:12.5px;letter-spacing:0.1px;color:#000;overflow-wrap:break-word;white-space:normal;text-transform:capitalize;}
/* A company/brand reference reads distinctly from a human name — lighter
   weight (Mata_04), full caps rather than Title Case, same size/color otherwise. */
.os-entry-person.is-business{font-weight:400;text-transform:uppercase;}
/* A record with no one assigned yet is still genuinely missing data — same
   pink prompt-not-blank treatment as an empty DATA cell, never a silent gap. */
.os-entry-person.is-missing{background:#ffe1d7;color:#ff7070;}
.os-entry-status{display:flex;align-items:center;padding:12.5px 10px;font-weight:700;font-size:10px;line-height:8.75px;letter-spacing:0.5px;text-transform:uppercase;overflow:hidden;}
/* A project live at more than one stage at once (Scope and Timeline, say —
   see projectLiveStages/liveProjectStages, os.js) stacks its labels here
   instead of picking one arbitrarily. Two is the realistic maximum and
   comfortably fits the row's own 90px min-height (see .os-entry-name). */
.os-entry-status--stacked{flex-direction:column;justify-content:center;gap:3px;padding-top:8px;padding-bottom:8px;}
.os-entry-status-line{display:block;}
/* STATUS renders as a real <button> (paid/pending toggle) on payable Vault
   records — strip the native button chrome the .os-entry-cell reset doesn't
   already cover so it's pixel-identical to the plain-text <span> case. */
button.os-entry-status{appearance:none;-webkit-appearance:none;margin:0;width:100%;cursor:pointer;transition:background .15s;}
button.os-entry-status:hover{background:rgba(0,0,0,0.12);}
.os-entry--attention button.os-entry-status:hover{background:#ffcbb5;}
.os-entry-notes{display:flex;align-items:center;gap:10px;padding:12.5px 10px;font-weight:700;font-size:8.75px;letter-spacing:0.07px;}
.os-entry-lines{flex:1;min-width:0;display:flex;flex-direction:column;font-size:8.75px;line-height:8.75px;overflow:hidden;}
/* An empty Notes placeholder reads quieter, not missing — there's nothing
   "waiting" about a note nobody's added yet. */
.os-entry-notes.is-empty{color:rgba(0,0,0,0.5);}
/* DATA is a stack of its own individually-filled entries (1–2) — the outer
   cell is unfilled, exactly like PERSONS; each line is its own pill so admin
   can see every data point as a distinct entry, not one shared block of text. */
.os-entry-data{display:flex;align-items:center;gap:10px;}
.os-entry-data-lines{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.os-entry-data-item{display:block;width:100%;padding:4px 10px;background:#eae8e8;border-radius:6px;box-sizing:border-box;font-family:"Project X",sans-serif;font-weight:700;font-size:8px;letter-spacing:0.07px;color:#000;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* A DATA item with nothing behind it names the field it's WAITING for, in
   pink — a prompt, not a blank. Only that one line, not the whole cell. */
.os-entry-data-item.is-missing{background:#ffe1d7;color:#ff7070;}
/* DATES — same stacked-pill shape as DATA (reuses .os-entry-data-item), always
   exactly two entries: Created, then Last Opened. System facts, never
   editable — stays plain text even while the row is being edited (see
   osEntryRow's datesCell, which never checks isEditingThis). */
.os-entry-dates{display:flex;align-items:center;gap:10px;}
.os-entry-dates-lines{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.os-entry-view{display:flex;align-items:center;justify-content:center;padding:7.5px 15px;font-weight:700;font-size:8.75px;line-height:8.75px;letter-spacing:0.35px;text-transform:uppercase;text-align:center;cursor:pointer;transition:background .15s;}
.os-entry-view:hover{background:rgba(0,0,0,0.12);}
/* LINK column — View/Edit stack the same way PERSONS does (1–2 lozenges,
   flex column); Save/Cancel take over that same slot while a row is being
   edited, so the column never changes shape, only what's in it. */
.os-entry-links{display:flex;flex-direction:column;justify-content:center;gap:2px;}
.os-entry-save{background:#edffd7;}
.os-entry-save:hover{background:#dcf5bb;}
.os-entry-cancel{color:rgba(0,0,0,0.5);}
/* Inline edit fields sit inside the SAME cell classes (.os-entry-name/
   .os-entry-person/etc already supply size, padding, background) — this just
   strips native input/select chrome so they read as the same lozenge, not a
   form control dropped on top of one. Text fields are contenteditable spans
   on the view element itself (not <input>) — only company (a real dropdown)
   is still a <select>. Deliberately NOT font/letter-spacing/background
   shorthand-style blanket overrides: those reset the property regardless of
   what the cell's own class (.os-entry-name/.os-entry-person/etc) already
   set, and since this rule comes later in the cascade it silently wins —
   that's what shrank the text (font:inherit) and killed the pill fill
   (background:transparent) the instant Edit was pressed. appearance:none
   already strips the native <select> chrome; nothing else needs resetting. */
.os-entry-input{appearance:none;-webkit-appearance:none;border:none;color:inherit;width:100%;min-width:0;}
.os-entry-input:focus{outline:1px solid rgba(0,0,0,0.3);outline-offset:-1px;border-radius:4px;}
select.os-entry-input{cursor:pointer;}
.os-entry-notes .os-entry-input{display:block;}
[contenteditable].os-entry-input{cursor:text;outline:none;}
[contenteditable].os-entry-input:empty:before{content:attr(data-placeholder);color:rgba(0,0,0,0.35);}
/* Rows inside a group are flush; .stack-rows' gap separates one record from
   the next. Editing a row must be an exact copy of its resting state —
   nothing visual turns on/off, only the editable cells themselves become
   editable and LINK swaps to Save/Cancel — so .os-entry-group--editing
   carries no styling of its own. */
.os-entry-group{display:flex;flex-direction:column;}

.os-row-meta{font-family:"Project X",sans-serif;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.4);white-space:nowrap;}
/* Client-name marker — one identity used everywhere a client/prospect is
   referenced (pipeline, documents, Today, prospects, clients). Transparent
   fill + border so it reads on any row surface: white, grey "big-button"
   rows, or the accent-green Today panel. */
.client-pill{display:inline-flex;align-items:center;height:var(--lozenge-h);font-family:"Project X",sans-serif;font-weight:700;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.55);background:transparent;border:0.5px solid rgba(0,0,0,0.18);border-radius:5px;padding:0.5px 8px 0;white-space:nowrap;}
.os-track{display:flex;gap:6px;align-items:center;flex-wrap:wrap;}
.os-stage{display:inline-flex;align-items:center;height:var(--lozenge-h);font-family:"Project X",sans-serif;font-weight:500;font-size:8px;letter-spacing:0.32px;text-transform:uppercase;padding:0.5px 11px 0;border-radius:5px;}
.os-stage-complete{background:#0000000f;color:#000;}
.os-stage-live{background:var(--accent);color:#000;}
.os-stage-incomplete{background:#0000000f;color:#000;opacity:0.5;}
/* Pipeline waiting indicator */
.os-waiting{display:inline-flex;align-items:center;height:var(--lozenge-h);font-family:"Project X",sans-serif;font-weight:500;font-size:8px;letter-spacing:0.4px;text-transform:uppercase;padding:0 8px;border-radius:5px;margin-left:8px;}
/* Send nudge — one-time prompt right after a proposal is created, so sending
   is a deliberate click rather than an implicit side-effect. Soft mint, same
   calm-positive tone as the Today panel. */
.os-send-nudge{display:flex;align-items:center;justify-content:space-between;gap:16px;background:#F6FFEB;border-radius:10px;padding:14px 20px;margin-bottom:16px;}
.os-send-nudge-msg{font-family:"Project X",sans-serif;font-weight:500;font-size:13px;color:#000;}
.os-send-nudge-actions{display:flex;gap:8px;flex-shrink:0;}
.os-stub,.os-create{background:#fff;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:28px;}
.os-stub-text{font-family:"Project X",sans-serif;font-size:13px;color:rgba(0,0,0,0.45);margin-top:10px;}
/* .os-project-page/-head/-heading/-title/-section (osProjectPage, os.js) are
   retired with that page — document-first-admin-surface-prompts.md,
   2026-09-04 — the floating .box (below) replaces it. */

/* ── THE RECORD BOX — floats on the live ?admin document ──
   document-first-admin-surface-prompts.md. Two .module cards (the exact
   white/bordered/rounded shell the Scope cards use on the document itself —
   see the real .module rule elsewhere in this file, not redefined here) plus
   a black header and a light footer. Position is inline (left/top, set by
   renderProjectBox/the drag handler in app.js) — only the chrome that never
   changes lives here. */
.box{background:#fff;border:0.5px solid rgba(0,0,0,0.12);border-radius:5px;box-shadow:0 10px 34px rgba(0,0,0,0.12);overflow:hidden;}
/* Collapsed: a small lozenge, not the open state's full-width bar — no
   width rule of its own (renderProjectBox, os.js, simply omits the inline
   width when collapsed), so a fixed-position box with nothing else sizing
   it shrinks to fit "Edit" + the toggle icon. The card chrome (white fill,
   border, shadow) is for framing .box-body/.box-foot; with neither present
   it's just dead space around the black head, so it's dropped here too.
   Radius is NOT overridden here on purpose — .box's own base radius is
   already the standard lozenge 5px (matches .pill), same in both states so
   there's nothing to reconcile when toggling. */
.box.is-collapsed{width:fit-content;background:transparent;border:none;box-shadow:none;}
.box.is-collapsed .box-head{height:var(--lozenge-h);padding:0 10px;gap:8px;}
/* Header is a fragment of the admin bar, not a title — same 28px, same
   black, same 9px/500 label as .admin-bar-fixed/.admin-bar-label. It says
   WHICH PROJECT this is (the bar itself now only says "Admin mode"), and
   it's the box's only control: mousedown+drag (app.js) moves it, a plain
   click collapses/reopens it — see boxDragEnd, app.js. */
.box-head{display:flex;align-items:center;justify-content:space-between;height:28px;padding:0 14px;background:#000;cursor:grab;user-select:none;}
.box-head:active{cursor:grabbing;}
.box-grip{width:26px;height:3px;border-radius:2px;background:rgba(255,255,255,0.22);flex-shrink:0;}
/* Own colour now, not inherited from the shared .admin-bar-label rule — that
   rule went dark-on-light when the real admin bar stopped being fixed black
   (see .admin-bar-fixed above); this header is still hardcoded black
   (.box-head) regardless, so it needs to keep the light text on its own. */
.box-head-label{color:rgba(255,255,255,.75);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}
/* Collapsed only — "Edit" is the box's one remaining affordance at lozenge
   size, so the LOZENGE ITSELF carries a slow shimmer (a soft diagonal band,
   repeating and swept via background-position) rather than sitting flat and
   easy to miss — a second, ambient way of drawing the eye to it beyond just
   its size. Lives on .box-head (the whole pill), not the label text — the
   text stays plain, readable white throughout; only .box's own overflow:
   hidden/border-radius (5px, matches every other lozenge) clips it to the
   pill shape. background-color kept separate from background-image so the
   solid black base isn't lost under the animated layer. */
.box.is-collapsed .box-head{
  background-color:#000;
  background-image:repeating-linear-gradient(100deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.22) 20%, rgba(255,255,255,0) 40%);
  background-size:300% 100%;
  animation:editShine 4s linear infinite;
}
@keyframes editShine{0%{background-position:0% 0;}100%{background-position:-300% 0;}}
@media (prefers-reduced-motion:reduce){
  .box.is-collapsed .box-head{animation:none;background-image:none;}
}
/* Plus collapsed, minus open — literally one path dropped, not a rotation
   (renderProjectBox, os.js, builds the two different path sets directly;
   there's no shared glyph animating between them the way the old chevron
   rotated). Deliberately not .ep-reference[open]>summary's chevron
   convention — this control reads better as an explicit expand/collapse
   pair at lozenge size. */
.box-toggle-icon{color:rgba(255,255,255,0.5);flex-shrink:0;}
.box-body{padding:14px;display:flex;flex-direction:column;gap:12px;}
.box-foot{padding:13px 14px;border-top:0.5px solid rgba(0,0,0,0.1);background:rgba(0,0,0,0.02);display:flex;gap:6px;flex-wrap:wrap;}
/* Inside a .module — one main-section name (.mod-head, same weight as a
   Scope card's own WHAT WE DO/WHAT YOU GET eyebrow: .col-label, reused
   verbatim), then one stacked .mod-row per sub-section. People sits on the
   exact off-white .modules-section already gives an editable document card
   (see that rule elsewhere in this file) — enough to tell Link and People
   apart without a label saying so. */
.mod-head{padding:11px 14px;border-bottom:0.5px solid rgba(0,0,0,0.08);}
.mod-row{padding:12px 14px;}
.mod-row+.mod-row{border-top:0.5px solid rgba(0,0,0,0.08);}
.mod-label{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.35);margin-bottom:8px;}
.box-name{font-family:"Project X",sans-serif;font-size:12px;font-weight:500;color:#000;}
/* Link data — 4 columns, 1 row; values wrap rather than truncate at 360px. */
.linkdata-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;}
/* Copy/Open — two single-icon lozenges beside the URL, same family as the
   timeline's own icon-only lozenge (.tl-iconbtn) just off --lozenge-h
   instead of the timeline's local --tl-loz-h. */
.loz-icon{display:inline-flex;align-items:center;justify-content:center;width:var(--lozenge-h);height:var(--lozenge-h);flex-shrink:0;border:none;border-radius:5px;background:#0000000f;color:#000;cursor:pointer;padding:0;}
.loz-icon svg{width:11px;height:11px;display:block;}
.loz-icon:hover{background:rgba(0,0,0,0.12);}
.team-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:3px 0;}
/* A lozenge (.os-linkbtn etc.) is reserved for something genuinely clickable
   — Full access/Working, Copy/Open, Publish, the four Link status toggles.
   NDA status and the Admin marker are never clicked, so they're an icon +
   label instead, no fill, no button-height box — .info-tag, not a lozenge. */
.info-tag{display:inline-flex;align-items:center;gap:5px;font-family:"Project X",sans-serif;font-weight:500;font-size:10px;letter-spacing:0.3px;text-transform:uppercase;color:rgba(0,0,0,0.4);}
.info-tag svg{width:11px;height:11px;flex-shrink:0;display:block;}
.info-tag.is-on{color:#000;}
/* Hover-revealed context, at the exact control it explains — a dotted
   underline marks anything that has more to say. Dark chip, same register
   as the box header/admin bar, so it reads as system chrome, not content.
   :focus-visible mirrors :hover — every non-button trigger below carries
   tabindex="0" so Tab reaches it too, not just a mouse. */
.tip{position:relative;}
.tip:not(button){cursor:help;}
.os-row-meta.tip,.box-name.tip{border-bottom:1px dotted rgba(0,0,0,0.3);}
.tip::after{content:attr(data-tip);position:absolute;left:0;bottom:calc(100% + 7px);width:max-content;max-width:220px;white-space:pre-line;background:#000;color:#fff;font-family:"Project X",sans-serif;font-size:10px;font-weight:500;line-height:1.4;letter-spacing:0;text-transform:none;padding:7px 9px;border-radius:6px;box-shadow:0 6px 20px rgba(0,0,0,0.2);opacity:0;transform:translateY(2px);pointer-events:none;transition:opacity .12s,transform .12s;z-index:80;}
/* Anchored from the right instead — for a trigger near the box's own right
   edge, where a left-anchored bubble would run past it. */
.tip-r::after{left:auto;right:0;}
.tip:hover::after,.tip:focus-visible::after{opacity:1;transform:translateY(0);}
.os-create-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-top:14px;}
.os-create-card{text-align:left;background:#F0F2EF;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:18px;cursor:pointer;transition:border-color .2s;}
.os-create-card:hover{border-color:rgba(0,0,0,0.3);}
.os-create-type{font-family:"Project X",sans-serif;font-weight:700;font-size:13px;letter-spacing:0.3px;text-transform:uppercase;}
.os-create-desc{font-family:"Project X",sans-serif;font-size:11px;line-height:1.3;color:rgba(0,0,0,0.45);margin-top:8px;}
/* OS — client-link controls (one home for what the ?admin dropdown used to hide) */
.os-ctrl-label{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.35);margin-top:14px;}
.os-ctrl-row{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;}
.os-ctrl-hint{display:flex;align-items:center;flex-wrap:wrap;gap:6px;font-family:"Project X",sans-serif;font-weight:500;font-size:11px;color:rgba(0,0,0,0.45);margin-top:10px;}
.os-panel{margin-bottom:16px;}
.os-hours-total{float:right;color:rgba(0,0,0,0.55);font-weight:600;}
.os-hours-row{display:flex;align-items:center;gap:12px;padding:8px 0;border-top:0.5px solid rgba(0,0,0,0.08);}
.os-hours-date{font-family:"Project X",sans-serif;font-size:9px;letter-spacing:0.3px;text-transform:uppercase;color:rgba(0,0,0,0.3);white-space:nowrap;}
.os-hours-amount{font-family:"Project X",sans-serif;font-weight:600;font-size:12px;color:#000;white-space:nowrap;}
.os-hours-note{font-family:"Project X",sans-serif;font-size:12px;color:rgba(0,0,0,0.5);}
.os-tool{position:relative;}
.os-tool-trigger{display:inline-flex;align-items:center;height:var(--lozenge-h);font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.55);background:rgb(228,230,227);border:none;border-radius:5px;padding:0.5px 12px 0;cursor:pointer;transition:background .15s,color .15s;}
.os-tool-trigger:hover{color:#000;}
/* Click-to-pin (osToolOpen, app.js/os.js), not hover — .is-open is a plain
   class toggle now, no :hover rule. Bounded + scrollable so it can never run
   off the bottom of the viewport regardless of how long Reference gets
   (28px = .admin-bar-fixed's own height). admin-bar-prompts.md PROMPT 4. */
.os-tool-pop{position:absolute;top:100%;right:0;margin-top:8px;display:none;width:300px;max-height:calc(100vh - 28px - 16px);overflow-y:auto;background:#fff;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:16px;z-index:45;box-shadow:0 10px 34px rgba(0,0,0,0.12);}
.os-tool-pop.is-open{display:block;}
.os-tool-pop>:first-child{margin-top:0;}
/* The project surface's old expand-in-place Edit panel (.admin-bar-fixed--
   expand/.admin-bar-row/.admin-bar-panel/.admin-bar-section + its light-on-
   dark inversion rules, admin-bar-expand-prompts.md PROMPT 2) is retired —
   document-first-admin-surface-prompts.md, 2026-09-04. That surface's bar is
   the plain .admin-bar-fixed mode notice now; its controls live in the
   floating .box instead (below). */
/* "Link" tool pop — two clearly separated sections (client-link controls, then
   activity stats), each with its own small caps label so the split reads
   instantly rather than looking like one long undifferentiated list. */
.os-tool-section-label{font-family:"Project X",sans-serif;font-weight:700;font-size:8px;letter-spacing:0.08em;text-transform:uppercase;color:rgba(0,0,0,0.35);margin-bottom:8px;}
.os-tool-section-divided{margin-top:14px;padding-top:14px;border-top:0.5px solid rgba(0,0,0,0.1);}
.os-tool-section-actions{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;}
.os-ws-linkurl{display:block;font-family:"Project X",sans-serif;font-size:11px;color:rgba(0,0,0,0.5);background:rgba(0,0,0,0.03);border:0.5px solid rgba(0,0,0,0.12);border-radius:5px;padding:5px 10px;width:100%;outline:none;}
/* The live project's link is real and fixed — shown as set/black text (not an
   editable field) since there's nothing to change it to. */
.os-ws-linkurl-fixed{color:#000;user-select:text;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* inline-flex + a 2px gap — same small-gap convention as .topnav-track and
   .os-nav-item — so any button that pairs a leading glyph ("+") with a label
   (e.g. +Prospect/+Teammate) spaces them consistently instead of relying on
   a literal text space. Single-text buttons (the majority) are unaffected —
   gap only applies between flex items, and there's only one here. */
.os-linkbtn{display:inline-flex;align-items:center;justify-content:center;gap:2px;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:#000;background:rgb(228,230,227);border:none;border-radius:5px;height:26px;padding:0 10px;cursor:pointer;transition:background .15s;}
.os-linkbtn:hover{background:rgb(200,203,197);}
/* Personal vs project on a new receipt — two named alternatives, so a pair of
   buttons with one selected, not a checkbox (see the Receipt branch of
   osNewDocModal). */
.os-receipt-kind{display:flex;gap:6px;}
.os-receipt-kind .os-linkbtn.is-on{background:var(--accent);box-shadow:inset 0 0 0 1px rgba(0,0,0,0.25);}
.os-panel{background:transparent;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:18px;}
/* Reference — collapsed by default (a plain <details>), the read-only half of
   editPanel (app.js). Native disclosure marker removed since .col-label's own
   display:flex already drops it in most browsers anyway; NAV_CHEVRON stands
   in for it instead, rotating open. admin-bar-prompts.md PROMPT 3. */
.ep-reference>summary{cursor:pointer;list-style:none;}
.ep-reference>summary::-webkit-details-marker{display:none;}
.ep-reference>summary .nav-chevron{margin-left:auto;transition:transform .15s;}
.ep-reference[open]>summary .nav-chevron{transform:rotate(180deg);}
/* The browser's own details:not([open])>:not(summary){display:none} UA rule
   is what actually hides a closed <details>' content — but reference's own
   children carry classes (.os-linkbtn, .os-ctrl-row, .os-track…) that set
   their OWN display, at higher specificity than that UA rule, and were
   winning: closed reference was toggling its chevron and [open] attribute
   while the content underneath stayed fully laid out and FOCUSABLE the whole
   time (caught by the Tab-trap acceptance check, not by eye — scrollHeight
   still dropped some, just not to the near-zero a real collapse gives).
   !important is the plain, correct tool here: this must beat EVERY display
   value anything inside reference could ever declare, not just today's. */
.ep-reference:not([open])>:not(summary){display:none!important;}
.os-story{margin-top:10px;}
.os-story-line{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;line-height:1.45;color:#000;}
.os-story-line+.os-story-line{margin-top:4px;}
.os-mini-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px;}
.os-mini-value{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;color:#000;margin-top:6px;}
.os-claude-input{width:100%;min-height:80px;margin-top:12px;font-family:"Project X",sans-serif;font-size:12px;color:#000;background:rgba(0,0,0,0.03);border:0.5px solid rgba(0,0,0,0.12);border-radius:6px;padding:10px;outline:none;resize:vertical;}
.os-claude-btn{margin-top:10px;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:#fff;background:#000;border:none;border-radius:5px;height:28px;padding:0 16px;opacity:0.4;cursor:not-allowed;}
/* Create-with-Claude — live drafting button + draft preview */
.os-claude-btn-live{opacity:1;cursor:pointer;}
.os-claude-btn-live:disabled{opacity:0.4;cursor:wait;}
.os-claude-btn-live:not(:disabled):hover{background:#222;}
.os-draft{margin-top:16px;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:18px;background:#F0F2EF;animation:calmIn .3s cubic-bezier(.16,1,.3,1);}
.os-draft-brief{font-family:"Project X",sans-serif;font-size:13px;font-weight:500;line-height:1.35;color:#000;margin-top:10px;}
.os-draft-mods{display:flex;flex-wrap:wrap;gap:6px;margin-top:14px;}
/* Person NDA mark — a quiet signed/unsigned indicator on a human's Persons
   row, same accent-green-when-true language as the module cert badge. */
.person-nda-mark{display:inline-flex;align-items:center;height:var(--lozenge-h);font-family:"Project X",sans-serif;font-weight:500;font-size:8px;letter-spacing:0.4px;text-transform:uppercase;padding:0.5px 8px 0;border-radius:5px;background:#0000000f;color:rgba(0,0,0,0.4);}
.person-nda-mark.is-signed{background:var(--accent);color:#3b4a2e;}
/* Mata_07 (weight 700) in every fillable OS field — search, forms, textareas. */
.os input,.os textarea{font-weight:700;}
/* Paid/pending control — a compact status pill that toggles on click, footprint
   matched to .os-linkbtn so it drops into the fixed actions slot. Pending reads as
   an actionable solid button ("mark paid"); paid settles into a done-grey fill. */
.os-paidpill{display:inline-flex;align-items:center;height:26px;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;padding:0 12px;border-radius:5px;border:none;background:rgb(228,230,227);color:rgba(0,0,0,0.6);cursor:pointer;transition:background .15s,color .15s;}
.os-paidpill:hover{background:rgb(200,203,197);color:#000;}
.os-paidpill.is-paid{background:#0000000f;color:#000;}
.os-btn-accent{background:var(--accent);}
.os-btn-accent:hover{background:#D8E0CF;}
.os-release-primary{height:32px;padding:0 16px;font-size:10px;}
/* Link-status's per-stage 3-point toggle (osBoxLinkModule, os.js) — stage
   name to the left, its 3 .os-linkbtn lozenges (Draft/Live/N/A) to the
   right, one line per stage rather than a name stacked above its own row —
   four of these read as four short rows, not four separate blocks. Fixed
   name width so all four rows' lozenge-groups line up regardless of
   "Proposal" vs "Delivery"'s length. */
.stage-toggle-row{display:flex;align-items:center;gap:8px;}
.stage-toggle-row+.stage-toggle-row{margin-top:6px;}
.stage-toggle-name{width:54px;flex-shrink:0;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.3px;text-transform:uppercase;color:rgba(0,0,0,0.45);}
/* Paid/pending toggle switch — state and control in one element, replacing a
   separate read-only badge + "Mark paid" button pair. */
.os-toggle{display:inline-flex;align-items:center;gap:7px;background:transparent;border:none;padding:0;cursor:pointer;}
.os-toggle-track{position:relative;width:30px;height:16px;border-radius:8px;background:rgba(0,0,0,0.15);transition:background .2s;flex-shrink:0;}
.os-toggle-thumb{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:6px;background:#fff;transition:transform .2s;}
.os-toggle.is-on .os-toggle-track{background:var(--accent);}
.os-toggle.is-on .os-toggle-thumb{transform:translateX(14px);}
.os-toggle-label{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;color:rgba(0,0,0,0.45);}
.os-toggle.is-on .os-toggle-label{color:#000;}
.os-search{flex:1;min-width:220px;font-family:"Project X",sans-serif;font-size:13px;color:#000;background:rgba(0,0,0,0.03);border:0.5px solid rgba(0,0,0,0.12);border-radius:6px;padding:9px 14px;outline:none;}
.os-search::placeholder{color:rgba(0,0,0,0.3);}
/* .os-nav-item — the one grey/active-black lozenge segment style, unscoped so
   any list's own filter/lens row can use it directly (Stack's lenses below,
   or anything else that needs this exact control). Pixel-matched to Figma
   node 3392:8519 ("Menu - Persons", MATA_OS file): 5px gap between a label
   and its trailing count/icon box (corrects an earlier V=188 assumption
   that this was the same 2px used BETWEEN lozenges in a row — that 2px is
   real, still on .stack-lenses/.topnav-track, but the gap INSIDE one
   lozenge, label to badge, was always meant to be 5px). Padding is
   left-only — the trailing box (.stack-count) is its own 25×25 square
   flush against the right edge, same background as the lozenge itself
   (inactive grey or active black), so it reads as one seamless pill. */
/* Translucent white + a frosted backdrop-blur: the stack-bar has no background
   of its own (it's sticky over the scrolling list), so each lozenge frosts the
   rows passing behind it — the label stays legible without a solid bar. The
   active lozenge is opaque black, so its blur is a no-op (nothing shows through
   solid black), which is fine. */
.os-nav-item{display:inline-flex;align-items:center;gap:5px;font-family:"Project X",sans-serif;font-weight:700;font-size:11px;letter-spacing:0.55px;text-transform:uppercase;color:rgb(0 0 0 / 34%);background:rgb(229 229 229 / 33%);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:black;border-radius:6px;height:var(--lozenge-h);padding:0 0 0 16px;cursor:pointer;transition:color .2s ease,background .2s ease;white-space:nowrap;}
.os-nav-item:hover{color:rgba(0,0,0,0.55);}
.os-nav-item.active{color:#fff;background:rgb(12,12,12);}

/* ── STACK — one filter bar, reused by every OS list ──
   LEFT lenses / MIDDLE facets / RIGHT find, same three zones every time. */
/* Sticky filter bar — the lens/search row stays pinned 2px under the sticky
   topnav (40px tall) as the list scrolls, so the filter controls are never
   lost mid-scroll. No background of its own (kept minimal, matching the
   topnav): the lozenges themselves carry a frosted translucent background
   (see .os-nav-item) so their labels stay legible over rows scrolling behind
   them. z-15 keeps the bar above the list but under the topnav; the Filter
   dropdown nested inside it (z-45) still overlays rows correctly since it
   lives within this bar's own stacking context. */
.stack-bar{position:sticky;top:var(--topnav-h,42px);z-index:15;display:flex;flex-direction:column;align-items:center;gap:2px;margin-bottom:64px;}
/* Row of .os-nav-item lens buttons — same 2px gap as .topnav-track, the
   other row of like-typed nav buttons. justify-content:center so a row that
   wraps on a narrow viewport keeps its second line centred too, instead of
   the line breaking left — align-items:center on the column above only
   centres each row as a whole, not what happens inside one once it wraps. */
.stack-lenses{display:flex;gap:2px;flex-wrap:wrap;justify-content:center;}
/* The trailing 25×25 box on an .os-nav-item — a count number (stack-lens)
   or a "+" glyph (the Filter trigger). No background/color of its own: it
   inherits both from the parent lozenge (grey/black, matching whichever
   state is active), which is what makes it read as one seamless pill
   rather than a button with a separate badge stuck on. */
.stack-count,.stack-filter-icon{display:inline-flex;align-items:center;justify-content:center;width:25px;height:25px;flex-shrink:0;}
.stack-count{font-size:8px;letter-spacing:0.4px;}
.stack-filter-icon{font-size:11px;}
.stack-tools{display:flex;align-items:center;justify-content:center;gap:2px;flex-wrap:wrap;}
.stack-facets{display:flex;align-items:center;justify-content:center;gap:2px;flex-wrap:wrap;}
.stack-facet-wrap{position:relative;}
.stack-filter-pop{position:absolute;top:100%;left:0;margin-top:8px;width:240px;background:#fff;border:0.5px solid rgba(0,0,0,0.12);border-radius:10px;padding:14px;z-index:45;box-shadow:0 10px 34px rgba(0,0,0,0.12);}
.stack-facet-group+.stack-facet-group{margin-top:12px;padding-top:12px;border-top:0.5px solid rgba(0,0,0,0.1);}
.stack-facet-label{font-family:"Project X",sans-serif;font-weight:700;font-size:8px;letter-spacing:0.08em;text-transform:uppercase;color:rgba(0,0,0,0.35);margin-bottom:8px;}
.stack-facet-opts{display:flex;flex-wrap:wrap;gap:4px;}
.stack-facet-opt{font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.3px;text-transform:uppercase;color:rgba(0,0,0,0.5);background:rgba(0,0,0,0.04);border:none;border-radius:5px;height:24px;padding:0 10px;cursor:pointer;}
.stack-facet-opt:hover{color:#000;}
.stack-facet-opt.active{color:#000;background:rgb(200,203,197);}
.stack-chip{display:inline-flex;align-items:center;gap:6px;font-family:"Project X",sans-serif;font-weight:500;font-size:9px;letter-spacing:0.3px;text-transform:uppercase;color:rgba(0,0,0,0.6);background:var(--accent);border:0.5px solid rgba(0,0,0,0.12);border-radius:5px;height:26px;padding:0 6px 0 10px;}
.stack-chip-x{font-size:11px;line-height:1;color:rgba(0,0,0,0.4);background:none;border:none;cursor:pointer;padding:2px;}
.stack-chip-x:hover{color:#000;}
/* Pixel-matched to Figma node 3392:8519: transparent fill (not .os-search's
   own subtle grey tint), 1px border (not 0.5px), and the same label
   typography as every lozenge here (11px/700/0.55px tracking, uppercase)
   rather than .os-search's plain 13px input text. */
/* Same frosted treatment as the lens lozenges (.os-nav-item) — the search box
   is part of the same sticky bar, so it frosts the rows behind it too rather
   than sitting transparent while everything beside it is legible. */
.stack-find{flex:0 0 auto;min-width:81px;max-width:100%;height:var(--lozenge-h);padding:0 15px;background:rgb(255 255 255 / 0%);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(0,0,0,0.1);border-radius:6px;font-size:11px;letter-spacing:0.55px;text-transform:uppercase;}
/* field-sizing:content lets the box grow with the typed term; a fixed width
   alongside it locks the flex-basis and blocks that growth in Chromium, so
   the auto-size override only applies where the property is understood —
   elsewhere it stays the plain 100px box above. */
@supports (field-sizing: content){
  .stack-find{field-sizing:content;width:auto;}
}
/* 40px between records — the gap the entry design puts between one group and
   the next (Figma: entries at y=134 and y=264, both 90 tall). Rows WITHIN a
   group stay flush; that's .os-entry-group's own job. */
.stack-rows{display:flex;flex-direction:column;gap:10px;overflow-x:auto;}
.os-invoice-form{margin-bottom:14px;}
.os-invoice-fields{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px;}
.os-invoice-paid{grid-column:1 / -1;display:flex;align-items:center;gap:8px;font-family:"Project X",sans-serif;font-size:12px;color:rgba(0,0,0,0.6);}
.os-invoice-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:14px;}
.os-team-projcheck{display:flex;align-items:center;gap:6px;font-family:"Project X",sans-serif;font-size:12px;color:rgba(0,0,0,0.6);}
/* Invoice In's primary field — the actual document, before any typed-in details.
   Solid grey until a file is chosen, then settles into a darker solid "has-file" state. */
.os-upload-primary{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;height:64px;border:none;border-radius:8px;background:rgb(228,230,227);color:rgba(0,0,0,0.5);font-family:"Project X",sans-serif;font-weight:500;font-size:11px;letter-spacing:0.3px;text-transform:uppercase;cursor:pointer;transition:color .2s,background .2s;}
.os-upload-primary:hover{background:rgb(200,203,197);color:#000;}
.os-upload-primary svg{width:16px;height:16px;flex-shrink:0;}
.os-upload-primary.has-file{background:#0000000f;color:#000;}

@media(max-width:600px){.os-invoice-fields{grid-template-columns:1fr;}}

@media(max-width:600px){
  /* ── .os-entry mobile pan — the desktop row, windowed ──
     The row is NOT restructured here: same eight cells, same order, same
     fills and type as desktop (see osEntryRow — mobile reuses the identical
     markup string). Only the width changes. The row is laid out three screens
     wide inside a one-screen clipping window, so at rest you see the first
     three cells and swipe that row sideways for the rest; the list itself
     still scrolls vertically. Every row is its own "osrow:<key>" surface, so
     rows pan independently — the pills bar moves them all at once.
     `translateX(-100%)` moves by 100% of the TRANSFORMED ELEMENT'S OWN box,
     not by "one window" — which is why .pan-group is left at its natural
     one-window width and .os-entry overflows it, rather than .pan-group
     itself being widened. Contrast the timeline's .vt .pan-group, which needs
     pixel math because its panels overlap a shared spine. */
  .os-entry-pan{width:100%;}
  /* 300% wide, and the eight fr shares below fall into three groups of 100 —
     WHO (22+48+30), STATE (30+38+32), NOTES (60+40) — so each group is exactly
     one window and each pan step lands flush on a group boundary. Change a
     share and its group must still total 100, or the steps drift off the
     cells. Group labels live in OSROW_PANELS (js/os.js). */
  .os-entry{grid-template-columns:22fr 48fr 30fr 30fr 38fr 32fr 60fr 40fr;width:300%;min-width:0;margin:0;}
  /* Desktop's 37.5px vertical padding exists to push a single-line name out to
     the 90px row height. In a ~160px-wide column that name wraps to two or
     three lines, and the padding would then stack ON TOP of them and balloon
     the row — min-height keeps the same 90px, so the padding's job is done. */
  .os-entry-name{padding:10px;}
  .os-entry--child .os-entry-name{padding:6px 10px;}
  /* At 8.75px line-height plus its padding, View/Edit is a ~26px target —
     fine for a cursor, well under the ~44px a thumb needs. Only the height
     changes; it stays the same cell in the same column. */
  .os-entry-view{min-height:44px;}
  /* Editing opts the row OUT of the pan (see osEntryRow) — every field stacks
     in one plain column so nothing being typed into can be panned off-screen. */
  .os-entry--editing-narrow{display:flex;flex-direction:column;gap:8px;width:100%;min-width:0;padding:10px 0;}
  .os-entry--editing-narrow .os-entry-name{padding:0;}
  /* Sticky, directly under the collapsed nav (same --topnav-h syncTopnavHeight()
     already maintains) so the pills stay reachable while the list scrolls. */
  .os-pan-pills-bar{position:sticky;top:var(--topnav-h,46px);z-index:19;background:#F0F2EF;padding:8px 0;display:flex;justify-content:center;}
  /* The Edit bar's own open region reaches mobile too (osTool, app.js/os.js
     — admin-bar-prompts.md PROMPT 4) — its buttons' base 26px (.os-linkbtn)
     is fine for a cursor, same story .os-entry-view's own min-height fix
     above already tells for this exact width. .admin-bar-panel is the
     project surface's expand-in-place panel (admin-bar-expand-prompts.md
     PROMPT 2); .os-tool-pop is the ?doc=/?record= popover, which still
     exists. Scoped to these two, not every .os-linkbtn in the OS — a
     deliberate, narrower fix, not a global touch-target pass never asked for. */
  .os-tool-pop .os-linkbtn,.admin-bar-panel .os-linkbtn{min-height:40px;}
}
/* padding-top stays the same 2px as desktop (not overridden here) — the
   stack-bar's lens/filter row sits directly under the topnav at any width;
   see .stack-bar's note on the two never visibly splitting apart. */
@media(max-width:720px){.os{padding:2px 20px 80px;}.os-create-grid{grid-template-columns:1fr;}}

/* ── PRINT — proposal / Scope / NDA / standalone docs print as real typeset
   documents: selectable text, honest page breaks, no UI chrome. The timeline
   and delivery states never reach here (raster path in downloadPDF). ── */
@media print{
  @page{size:A4;margin:14mm;}
  html,body{background:#fff;}
  *{-webkit-print-color-adjust:exact;print-color-adjust:exact;}
  /* single-document prints (invoices): swap the app for the injected doc */
  body.printing-doc #root{display:none!important;}
  body.printing-doc #print-doc{display:block;}
  body.printing-doc #print-doc .invoice-doc{width:auto;min-height:auto;padding:0;}
  /* chrome off the page */
  .topnav,.mata-lozenge-fixed,.proposal-pagenum-fixed,.prop-swipehint-fixed,.prop-express,.landing,.modal-backdrop,.lib-backdrop,
  .pdf-btn-wrap,.footer-url,.page-actions,.mod-remove,.back-cover-btn,
  .page-spacer,.orient-line,.quote-dot-row{display:none!important;}
  .page{width:100%;max-width:none;background:#fff;padding-bottom:0;}
  /* nothing splits mid-block */
  .approach,.quote-gallery,.module,.needs-overview,.legal-master,
  .final-sign,.nda-intro,.approach-col,
  .challenges-card,.back-cover,.doc-draft-band,.scope-terms{break-inside:avoid;}
  /* paged rhythm — the 200px screen breaths become document spacing */
  .page-proposal .approach,.page-proposal .approach-method,.page-proposal .modules-section,
  .back-cover{margin-top:48px;}
  .page-proposal .modules{gap:16px;}
  .page-proposal .hero-compact{padding-top:0;margin-top:24px;}
  /* admin editing affordances never print */
  .ae{box-shadow:none!important;background:transparent!important;}
  .ae:empty{display:none!important;}
}
