/*
 * core.css: the platform shell. Tokens, the ten themes, font sets, block
 * styles, the rail, controls, panels, rows, modals, the dashboard grid, global
 * search, the mobile navigation, the settings launcher and the dock.
 *
 * Nothing feature-shaped lives here. A module ships its own
 * public/assets/modules/{key}/module.css carrying its .row.<feature> grid
 * lines and its screens, loaded after this file.
 *
 * Carved from GnomeWork's app.css. Comments explaining WHY a rule is the way
 * it is were kept on purpose: most of them record a measurement.
 */

  :root{
    --ink:#1F3A34; --ink-soft:#3E5850;
    --paper:#F5F1E8; --paper-raised:#FFFFFF;
    --line:#DAD3C2; --line-strong:#C3BAA4;
    --mustard:#B8792E; --mustard-soft:#EFDFC7;
    --sage:#7C9082; --sage-soft:#E4E9DF;
    --brick:#B8433C; --brick-soft:#F3DEDB;
    --blue:#3E6E8E; --blue-soft:#DDE8EE;
    --green-dot:#4C8B5C; --yellow-dot:#D4A62B;
    --text-muted:#8A8570; --subtle-bg:#FBF9F3; --radius:6px;
    /*
     * Typography. A font set swaps display and ui; --font-mono never changes,
     * because it is doing alignment work in counts, SKUs and money columns
     * rather than decoration, and a proportional face there would break the
     * columns. Sets live in the html[data-font=…] blocks further down.
     */
    --font-display:'Fraunces', serif;
    --font-ui:'IBM Plex Sans', sans-serif;
    --font-mono:'IBM Plex Mono', monospace;
    /*
     * Block style - how content panels are drawn. Every content panel reads
     * these, so a style is six declarations rather than a hunt through the
     * stylesheet. Chrome that isn't content (modals, dropdowns, the floating
     * chat panel) deliberately doesn't use them: a dropdown with no border
     * because somebody chose Flat would be unreadable over the page behind it.
     */
    --panel-bg:var(--paper-raised);
    --panel-border:1px solid var(--line);
    --panel-radius:8px;
    --panel-pad:16px 18px;
    --panel-shadow:none;
    --row-pad:13px 16px;
    /* Nav category tints. Every group head is a filled band so it can't be
       mistaken for one of the tabs underneath it. Each family needs a soft
       fill AND a matching dark ink - text on a tint must come from the same
       hue, or it reads as a mistake. Plum and teal are new: the palette had
       four usable families and there are seven groups. Apps is violet rather
       than the obvious green because green sits on top of CRM's sage - two
       adjacent groups reading as the same colour defeats the point. */
    --violet:#6A6AA8; --violet-soft:#E3E2F2;
    --plum:#8A5A7A; --plum-soft:#EDE0E8;
    --teal:#3E8E85; --teal-soft:#DAEBE8;
    --sage-ink:#3A5240; --mustard-ink:#7A4E17; --blue-ink:#2A4C63;
    --violet-ink:#3F3F73; --brick-ink:#8A2F29; --plum-ink:#6B4159;
    --teal-ink:#2C6660;
  }
  /*
   * Themes. `:root` above is Garden paper, the default, so a theme block only
   * has to restate what differs - except that in practice every block restates
   * ALL of them. A theme that overrode only paper and ink would inherit Garden
   * paper's nav tints, and the sidebar headers would come out as pale mint on a
   * dark background. Copy a whole block when adding one.
   *
   * `data-theme` names the specific theme; `data-scheme` says light or dark and
   * is what the handful of scheme-specific rules below key on, so adding a
   * fourth dark theme doesn't mean editing ten selectors. applyTheme() sets
   * both.
   */

  /*
   * Block styles. Framed is :root, so it needs no block.
   *
   * Elevated is the only one that has to know about the colour scheme: a shadow
   * tuned for cream paper disappears on a near-black one. That is what
   * data-scheme is for, and why it exists separately from data-theme - one rule
   * covers all five dark themes.
   */
  html[data-blocks="flat"]{
    --panel-bg:var(--subtle-bg);
    --panel-border:1px solid transparent;
    --panel-shadow:none;
  }
  html[data-blocks="elevated"]{
    --panel-border:1px solid transparent;
    --panel-radius:12px;
    --panel-shadow:0 2px 8px rgba(31,58,52,0.10), 0 1px 2px rgba(31,58,52,0.06);
  }
  html[data-scheme="dark"][data-blocks="elevated"]{
    --panel-shadow:0 2px 10px rgba(0,0,0,0.45), 0 1px 3px rgba(0,0,0,0.35);
  }
  /* No panels at all. The section heading and its rule do the separating, the
     way a printed report does it. Rows keep their own dividers, or a list would
     become an undifferentiated block of text. */
  html[data-blocks="ruled"]{
    --panel-bg:transparent;
    --panel-border:none;
    --panel-radius:0;
    --panel-pad:0;
    --panel-shadow:none;
  }
  html[data-blocks="ruled"] .section-head{border-bottom:1px solid var(--line);padding-bottom:8px;}
  html[data-blocks="ruled"] .row{padding-left:0;padding-right:0;}
  html[data-blocks="compact"]{
    --panel-radius:4px;
    --panel-pad:10px 12px;
    --row-pad:8px 12px;
  }

  /*
   * Font sets. Garden is :root, so it needs no block. `system` deliberately
   * names no web font at all - it downloads nothing and never flashes.
   */
  html[data-font="plain"]{--font-display:'Inter', sans-serif;--font-ui:'Inter', sans-serif;}
  html[data-font="legible"]{--font-display:'Atkinson Hyperlegible', sans-serif;--font-ui:'Atkinson Hyperlegible', sans-serif;}
  html[data-font="editorial"]{--font-display:'Source Serif 4', serif;--font-ui:'Source Sans 3', sans-serif;}
  html[data-font="system"]{--font-display:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;--font-ui:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;}
  html[data-font="slab"]{--font-display:'Zilla Slab', serif;--font-ui:'IBM Plex Sans', sans-serif;}
  html[data-font="storybook"]{--font-display:'EB Garamond', serif;--font-ui:'Lato', sans-serif;}
  html[data-font="rounded"]{--font-display:'Nunito', sans-serif;--font-ui:'Nunito', sans-serif;}
  html[data-font="condensed"]{--font-display:'Archivo Narrow', sans-serif;--font-ui:'Archivo', sans-serif;}
  html[data-font="technical"]{--font-display:'Space Grotesk', sans-serif;--font-ui:'IBM Plex Sans', sans-serif;}
  html[data-font="physare"]{--font-display:'Helvetica Neue', Helvetica, Arial, sans-serif;--font-ui:'Helvetica Neue', Helvetica, Arial, sans-serif;}
  /* DM Sans throughout, as the set promises: figures and column headings too,
     which took the base IBM Plex Mono (Nick, 2026-10-19). Even-width digits
     keep a column of numbers lined up the way the monospace did. */
  html[data-font="grainpath"]{--font-display:'DM Sans', sans-serif;--font-ui:'DM Sans', sans-serif;--font-mono:'DM Sans', sans-serif;font-variant-numeric:tabular-nums;}
  /* The house face is light, not bold: Helvetica at 600 reads as shouting on black. */
  html[data-font="physare"] .brand-mark{font-weight:400;letter-spacing:-0.025em;}
  html[data-font="physare"] .page-title,html[data-font="physare"] h2,html[data-font="physare"] .section-title{font-weight:500;letter-spacing:-0.015em;}

  /* Ink and linen - cool light, navy ink. The plain counterpart to Garden paper. */
  html[data-theme="ink"]{
    --ink:#232A33; --ink-soft:#4A5462;
    --paper:#F4F4F1; --paper-raised:#FFFFFF;
    --line:#DCDCD6; --line-strong:#C2C2BA;
    --mustard:#A9761F; --mustard-soft:#F0E1C6;
    --sage:#5E8A6B; --sage-soft:#DEE9E1;
    --brick:#B23A3A; --brick-soft:#F3DCDC;
    --blue:#2C5F8A; --blue-soft:#D9E5EF;
    --green-dot:#3F7C4E; --yellow-dot:#B98F1E;
    --text-muted:#7D8590; --subtle-bg:#FAFAF8;
    --violet:#5B5FA6; --violet-soft:#E0E1F2;
    --plum:#8A4F77; --plum-soft:#EEDFE9;
    --teal:#2F8078; --teal-soft:#D8EAE7;
    --sage-ink:#2F4F39; --mustard-ink:#6E4A11; --blue-ink:#1E4160;
    --violet-ink:#383B75; --brick-ink:#7C2727; --plum-ink:#5E3550;
    --teal-ink:#235B55;
  }

  /* Moss - Garden paper with the colour turned up. */
  html[data-theme="moss"]{
    --ink:#16301F; --ink-soft:#375040;
    --paper:#EFF2EA; --paper-raised:#FDFEFB;
    --line:#D2DBC9; --line-strong:#B4C2A8;
    --mustard:#A9761B; --mustard-soft:#F1E2C3;
    --sage:#4E7F58; --sage-soft:#D8E7D9;
    --brick:#A83B34; --brick-soft:#F2DCD9;
    --blue:#2C6480; --blue-soft:#D7E6ED;
    --green-dot:#3B7A47; --yellow-dot:#B08B1C;
    --text-muted:#75856E; --subtle-bg:#F6F9F2;
    --violet:#5C5A9E; --violet-soft:#DFDEF0;
    --plum:#83486F; --plum-soft:#EDDDE7;
    --teal:#2A7B6B; --teal-soft:#D5E9E3;
    --sage-ink:#234A2C; --mustard-ink:#6B4A0F; --blue-ink:#1C4256;
    --violet-ink:#343267; --brick-ink:#6E241E; --plum-ink:#522B44;
    --teal-ink:#175044;
  }

  /* Newsprint - near-monochrome light. Colour appears only where it carries
     meaning, so status badges do more work. */
  html[data-theme="newsprint"]{
    --ink:#1A1A18; --ink-soft:#44443F;
    --paper:#F7F7F5; --paper-raised:#FFFFFF;
    --line:#DEDEDA; --line-strong:#BFBFB9;
    --mustard:#8F7031; --mustard-soft:#EFE6D5;
    --sage:#55705C; --sage-soft:#E2E7E2;
    --brick:#96453F; --brick-soft:#EEDFDD;
    --blue:#3C5C74; --blue-soft:#DFE6EB;
    --green-dot:#4A7355; --yellow-dot:#A8862A;
    --text-muted:#75756E; --subtle-bg:#FCFCFA;
    --violet:#55538A; --violet-soft:#E4E3EC;
    --plum:#7A5069; --plum-soft:#EBE1E7;
    --teal:#37716B; --teal-soft:#DEE9E7;
    --sage-ink:#2C3D31; --mustard-ink:#56421A; --blue-ink:#22384A;
    --violet-ink:#333155; --brick-ink:#5E2A26; --plum-ink:#4B2F40;
    --teal-ink:#1E443F;
  }

  /* Sandstone - warm neutral light. Garden paper without the green cast. */
  html[data-theme="sandstone"]{
    --ink:#332C24; --ink-soft:#574C40;
    --paper:#F4EFE6; --paper-raised:#FFFCF7;
    --line:#E2D9CB; --line-strong:#C9BCA8;
    --mustard:#A5741F; --mustard-soft:#F1E1C4;
    --sage:#6F8368; --sage-soft:#E3E8DC;
    --brick:#A9463A; --brick-soft:#F2DED9;
    --blue:#3E6479; --blue-soft:#DCE6EB;
    --green-dot:#4F7F55; --yellow-dot:#BE9425;
    --text-muted:#8B7F6E; --subtle-bg:#FAF6EF;
    --violet:#635A93; --violet-soft:#E4E1EF;
    --plum:#8B5271; --plum-soft:#EFDFE7;
    --teal:#357C71; --teal-soft:#D9E8E4;
    --sage-ink:#3B4A33; --mustard-ink:#684711; --blue-ink:#2A4453;
    --violet-ink:#3A3563; --brick-ink:#6F2A21; --plum-ink:#573044;
    --teal-ink:#1F4E46;
  }

  /* Slate - cool grey-blue dark. Replaces the old "dark" theme. */
  html[data-theme="slate"]{
    --ink:#E6EAF0; --ink-soft:#B9C2CD;
    --paper:#1B1F24; --paper-raised:#242A31;
    --line:#333B45; --line-strong:#46505C;
    --mustard:#D9A25A; --mustard-soft:#3D3320;
    --sage:#8FB09A; --sage-soft:#26332B;
    --brick:#E08078; --brick-soft:#3D2422;
    --blue:#6FA8D0; --blue-soft:#1F2E39;
    --green-dot:#6FC486; --yellow-dot:#E4BE58;
    --text-muted:#8994A1; --subtle-bg:#2C333B;
    --violet:#9B9BE0; --violet-soft:#2B2B40;
    --plum:#C08BB4; --plum-soft:#362534;
    --teal:#6BBDB4; --teal-soft:#1D3330;
    --sage-ink:#BCD4C4; --mustard-ink:#EBCB92; --blue-ink:#BBD9EC;
    --violet-ink:#C7C7EE; --brick-ink:#F0B4AC; --plum-ink:#E0BCD5;
    --teal-ink:#A8D9D2;
  }

  /* Dusk - deep indigo dark. */
  html[data-theme="dusk"]{
    --ink:#E4E3EE; --ink-soft:#B6B5C6;
    --paper:#15161F; --paper-raised:#1E2029;
    --line:#2E3040; --line-strong:#414459;
    --mustard:#DDA65E; --mustard-soft:#3B3120;
    --sage:#86B396; --sage-soft:#223026;
    --brick:#E58A83; --brick-soft:#3C2429;
    --blue:#7BAEE0; --blue-soft:#1E2C3E;
    --green-dot:#6BC384; --yellow-dot:#E5C264;
    --text-muted:#8A89A0; --subtle-bg:#262838;
    --violet:#A6A2EC; --violet-soft:#2A2846;
    --plum:#C892BC; --plum-soft:#34253A;
    --teal:#6FC3BC; --teal-soft:#1C3134;
    --sage-ink:#BDD8C6; --mustard-ink:#EFCE99; --blue-ink:#BEDBF1;
    --violet-ink:#CFCCF4; --brick-ink:#F2B8B2; --plum-ink:#E4C2DC;
    --teal-ink:#ABDDD8;
  }

  /* Ember - warm dark. The only one of the three darks without a cool cast. */
  html[data-theme="ember"]{
    --ink:#F0E7DE; --ink-soft:#CBBCAF;
    --paper:#1E1A17; --paper-raised:#292421;
    --line:#3D3530; --line-strong:#504640;
    --mustard:#E0A455; --mustard-soft:#45341D;
    --sage:#9CB08C; --sage-soft:#2C3527;
    --brick:#E5867A; --brick-soft:#432723;
    --blue:#86AEC4; --blue-soft:#263239;
    --green-dot:#83C48F; --yellow-dot:#E8C46A;
    --text-muted:#968779; --subtle-bg:#332C28;
    --violet:#B0A0D4; --violet-soft:#322C40;
    --plum:#C58FA8; --plum-soft:#3A2A32;
    --teal:#6FBDAE; --teal-soft:#21332F;
    --sage-ink:#C8D8BC; --mustard-ink:#F2CE96; --blue-ink:#BDD6E3;
    --violet-ink:#D6CCEC; --brick-ink:#F4B7AE; --plum-ink:#E5C3D2;
    --teal-ink:#ADDBD1;
  }

  /* Obsidian - near-black neutral. The highest-contrast of the darks. */
  html[data-theme="obsidian"]{
    --ink:#F2F3F5; --ink-soft:#C3C6CC;
    --paper:#0E0F11; --paper-raised:#17191C;
    --line:#282B30; --line-strong:#3A3E45;
    --mustard:#E5AE63; --mustard-soft:#3A2F1C;
    --sage:#93BCA0; --sage-soft:#1D2A21;
    --brick:#EC8B81; --brick-soft:#3A2220;
    --blue:#7DB6E2; --blue-soft:#182833;
    --green-dot:#79CE90; --yellow-dot:#EBC85E;
    --text-muted:#909499; --subtle-bg:#1D2024;
    --violet:#A9A6F0; --violet-soft:#242347;
    --plum:#D096C2; --plum-soft:#331F30;
    --teal:#71C8BE; --teal-soft:#152E2B;
    --sage-ink:#C3DDCB; --mustard-ink:#F3D3A0; --blue-ink:#C4DEF3;
    --violet-ink:#D3D1F7; --brick-ink:#F6BCB4; --plum-ink:#EAC6E0;
    --teal-ink:#AFE0D9;
  }

  /* Physare: black, charcoal and three greys, with ONE colour, the yellow of
     the Physare mark, carrying the accent (active tab, primary button, paid).
     Every other family is desaturated towards grey so a status still reads
     without breaking the monochrome. */
  html[data-theme="physare"]{
    /* Native controls (checkbox, radio, range, the date picker) take the
       yellow too; without accent-color they are browser blue, the one colour
       this theme must never show. */
    accent-color:#E9F26B; color-scheme:dark;
    --ink:#E8E8E6; --ink-soft:#A6A6A3;
    --paper:#0B0B0C; --paper-raised:#141416;
    --line:#232325; --line-strong:#3A3A3E;
    --mustard:#E9F26B; --mustard-soft:#26281A;
    --sage:#E9F26B; --sage-soft:#1F2210;
    --brick:#D08A82; --brick-soft:#2A1F1E;
    --blue:#9CA3AD; --blue-soft:#1C1E22;
    --green-dot:#E9F26B; --yellow-dot:#E9F26B;
    --text-muted:#6B6B69; --subtle-bg:#1A1A1C;
    --violet:#A9A9B5; --violet-soft:#1E1E24;
    --plum:#B3A3AE; --plum-soft:#221D21;
    --teal:#9DB0AD; --teal-soft:#1B2221;
    --sage-ink:#E9F26B; --mustard-ink:#E9F26B; --blue-ink:#D6D6D3;
    --violet-ink:#D6D6D3; --brick-ink:#E8B3AC; --plum-ink:#D6D6D3;
    --teal-ink:#D6D6D3;
  }

  /* Forest - deep green dark, the green-black the retired Nightshade had. */
  html[data-theme="forest"]{
    --ink:#E7EFE4; --ink-soft:#BCCBB7;
    --paper:#101A13; --paper-raised:#19251C;
    --line:#2A3A2C; --line-strong:#3C4E3E;
    --mustard:#D6A356; --mustard-soft:#3C3320;
    --sage:#8CBE97; --sage-soft:#213022;
    --brick:#E28B7E; --brick-soft:#3B2523;
    --blue:#7FB3CC; --blue-soft:#1B2F37;
    --green-dot:#71CB86; --yellow-dot:#E1C25D;
    --text-muted:#849081; --subtle-bg:#1E2C21;
    --violet:#A29ED8; --violet-soft:#292B40;
    --plum:#C08FAF; --plum-soft:#372936;
    --teal:#6BC0B0; --teal-soft:#173330;
    --sage-ink:#BFDBC6; --mustard-ink:#EDCE97; --blue-ink:#BFDAE9;
    --violet-ink:#CBC8EE; --brick-ink:#F1B9AF; --plum-ink:#E2C1D6;
    --teal-ink:#A7DCD2;
  }
  html[data-scheme="dark"] .badge.pending{color:#E8C98A;}
  html[data-scheme="dark"] .badge.fulfilled{color:#BFE0C6;}
  html[data-scheme="dark"] .badge.paid{color:#12281A;}
  html[data-scheme="dark"] .badge.consigned{color:#BFDCEA;}
  html[data-scheme="dark"] .badge.st-waiting{color:#E8C98A;}
  html[data-scheme="dark"] .badge.st-progress{color:#BFDCEA;}
  html[data-scheme="dark"] .badge.st-done{color:#BFE0C6;}
  html[data-scheme="dark"] .badge.sentiment-not{color:#F0B7AE;}
  html[data-scheme="dark"] .badge.sentiment-follow{color:#BFDCEA;}
  html[data-scheme="dark"] .badge.sentiment-nurture{color:#BFE0C6;}
  html[data-scheme="dark"] .badge.warn{color:#F0B7AE;}
  html[data-scheme="dark"] .badge.sentiment-connected{color:#12281A;}
  /* Physare badges stay in its own greys and yellow: the dark-scheme blues
     above would be the only blue on the page. Waiting and done wear the
     yellow; progress, consigned and follow-up are quiet grey. */
  html[data-theme="physare"] .badge.pending,html[data-theme="physare"] .badge.st-waiting{color:#E9F26B;}
  html[data-theme="physare"] .badge.fulfilled,html[data-theme="physare"] .badge.st-done,html[data-theme="physare"] .badge.sentiment-nurture{color:#E9F26B;}
  html[data-theme="physare"] .badge.consigned,html[data-theme="physare"] .badge.st-progress,html[data-theme="physare"] .badge.sentiment-follow{background:var(--subtle-bg);color:var(--ink);}
  body{transition:background-color 0.15s ease, color 0.15s ease;}
  *{box-sizing:border-box;}
  body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--font-ui);-webkit-font-smoothing:antialiased;}
  .app{max-width:none;margin:0 auto;display:grid;grid-template-columns:220px 1fr;min-height:100vh;}
  /* minmax(0,1fr), not 1fr: a plain 1fr never goes below its content's narrowest, so one
     row of unwrapped buttons widened the whole phone page and it zoomed out to fit. */
  @media (max-width:820px){ .app{grid-template-columns:minmax(0,1fr);} .rail{position:sticky;top:0;z-index:30;} }

  .rail{border-right:1px solid var(--line);padding:28px 18px;display:flex;flex-direction:column;gap:18px;background:var(--paper);}
  @media (max-width:820px){ .rail{border-right:none;border-bottom:1px solid var(--line);flex-direction:row;align-items:center;padding:14px 18px;gap:14px;} }

  .brand{display:flex;align-items:baseline;gap:8px;}
  .brand-mark{font-family:var(--font-display);font-weight:600;font-size:21px;letter-spacing:-0.01em;}
  /* The lockup: the name, and the vendor's byline small and spaced beneath it. */
  .brand-lockup{display:flex;flex-direction:column;line-height:1;}
  /* The mark stands as tall as the name and byline together and is centred on
     them, rather than hanging off the name's baseline. */
  .rail .brand-logo{height:32px;max-width:60px;align-self:center;}
  .rail .brand:has(.brand-logo){gap:7px;}
  .rail .brand:has(.brand-logo) .rail-toggle{margin-left:0;width:28px;}
  @media (max-width:820px){ .rail .brand-logo{height:26px;} }
  .brand-byline{display:block;font-family:var(--font-ui);font-size:9px;letter-spacing:0.22em;text-transform:uppercase;color:var(--text-muted);margin-top:5px;}
  .brand-sub{font-family:var(--font-mono);font-size:10px;color:var(--text-muted);letter-spacing:0.08em;text-transform:uppercase;margin-top:-12px;}
  /* The notification bell, at the right-hand end of the brand row. align-self
     overrides the row's baseline alignment, which would hang an icon off the
     title's baseline; the badge is its own positioned child. Its display is
     toggled inline by renderNotificationBell(), which is why the mobile rule
     below needs !important: that rail has its own bell. */
  .brand-bell{display:inline-flex;align-items:center;align-self:center;margin-left:auto;cursor:pointer;position:relative;color:var(--text-muted);}
  .brand-bell:hover{color:var(--ink);}
  .brand-bell .ic{width:19px;height:19px;}
  #notif-count{position:absolute;top:-6px;right:-8px;min-width:15px;height:15px;border-radius:8px;background:var(--brick);color:#fff;font-size:9px;line-height:15px;text-align:center;padding:0 3px;font-family:var(--font-mono);}
  @media (max-width:820px){ .brand-sub{display:none;} .brand{flex-shrink:0;} .brand-mark{font-size:17px;} .brand-bell{display:none !important;} }

  .tabs{display:flex;flex-direction:column;gap:2px;flex:1;}
  @media (max-width:820px){ .tabs{flex-direction:row;flex:1;flex-wrap:wrap;} }
  .tab{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 12px;border-radius:var(--radius);font-size:14px;color:var(--ink-soft);cursor:pointer;white-space:nowrap;border:1px solid transparent;transition:background 0.12s ease;}
  .tab:hover{background:var(--sage-soft);}
  .tab.active{background:var(--paper-raised);border-color:var(--line);color:var(--ink);font-weight:500;}
  .tab .count{font-family:var(--font-mono);font-size:11px;color:var(--text-muted);}
  .tab.active .count{color:var(--mustard);}

  /* Outline icons, drawn from the sprite in index.html.
     `stroke:currentColor` is the whole reason this works across ten themes and
     five dark ones: the icon inherits .tab's colour, so it lightens on hover
     and darkens with .tab.active without a single extra rule. Never give an
     icon its own colour here or that stops being true.
     A .tab is display:flex with space-between, so the icon and label have to
     share ONE flex child (.tab-label) or the count gets pushed into the middle. */
  .ic{width:17px;height:17px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;}
  .tab-label{display:flex;align-items:center;gap:9px;min-width:0;overflow:hidden;text-overflow:ellipsis;}
  /* Buttons are inline rather than flex, so the icon is aligned optically
     against the text baseline instead of being centred by the layout. */
  .btn .ic{vertical-align:-3.5px;margin-right:5px;width:15px;height:15px;}
  .page-title .ic{width:21px;height:21px;vertical-align:-3px;margin-right:8px;}

  .tab-group{position:relative;}
  .submenu{display:none;position:absolute;left:100%;top:0;margin-left:6px;background:var(--paper-raised);border:1px solid var(--line);border-radius:8px;min-width:170px;padding:4px;z-index:40;box-shadow:0 4px 14px rgba(31,58,52,0.12);}
  .tab-group:hover .submenu{display:block;}
  @media (max-width:820px){ .submenu{left:0;top:100%;margin-left:0;margin-top:4px;} }
  .submenu-item{padding:8px 10px;border-radius:5px;font-size:13px;color:var(--ink-soft);cursor:pointer;display:flex;align-items:center;gap:8px;white-space:nowrap;}
  .submenu-item:hover{background:var(--sage-soft);color:var(--ink);}
  .submenu-item .count{margin-left:auto;}

  /*
   * Theme picker. Each swatch has to show ITS OWN colours, not the active
   * theme's - a `data-theme` attribute on an element inside the page doesn't
   * pick up the html[data-theme=…] blocks, so the four colours each swatch
   * needs are restated here. Keep them in step with the theme blocks above; a
   * swatch that lies about a theme is worse than no swatch.
   */
  /* Five across, two down. The count is fixed rather than auto-fit because
     auto-fit lands on three or four columns at some widths, and ten themes
     across three columns leaves a ragged last row - which is the thing this
     grid exists to avoid. Both 5 and 2 divide ten exactly. */
  /* The sample under the font dropdown. Always rendered in the current choice,
     because browsers vary in how faithfully they style <option> text and the
     dropdown alone can't be trusted to show the difference. */
  .font-sample{display:flex;flex-direction:column;gap:3px;margin-top:12px;padding:12px 14px;background:var(--subtle-bg);border:1px solid var(--line);border-radius:var(--radius);}
  .font-sample-display{font-family:var(--font-display);font-size:19px;font-weight:600;color:var(--ink);}
  .font-sample-ui{font-family:var(--font-ui);font-size:13px;color:var(--ink-soft);}
  .font-sample-mono{font-family:var(--font-mono);font-size:12px;color:var(--text-muted);}


  .block-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;}
  @media (max-width:900px){ .block-grid{grid-template-columns:repeat(1,1fr);} }
  /*
   * The block preview draws its own treatment rather than inheriting the
   * active one - the same reason the theme swatches restate their colours.
   * These are literal values, not the --panel-* variables, or every card would
   * show whichever style is already applied.
   */
  .block-preview{display:block;background:var(--paper);border-radius:5px;padding:7px;height:52px;}
  .block-preview-panel{display:flex;flex-direction:column;gap:4px;height:100%;background:var(--paper-raised);border:1px solid var(--line);border-radius:6px;padding:7px 8px;}
  .block-preview-title{display:block;height:6px;width:52%;border-radius:2px;background:var(--ink-soft);}
  .block-preview-line{display:block;height:4px;border-radius:2px;background:var(--line-strong);}
  .block-preview-line.short{width:60%;}
  .block-preview[data-blocks="flat"] .block-preview-panel{background:var(--subtle-bg);border-color:transparent;}
  .block-preview[data-blocks="elevated"] .block-preview-panel{border-color:transparent;border-radius:9px;box-shadow:0 2px 6px rgba(31,58,52,0.16);}
  html[data-scheme="dark"] .block-preview[data-blocks="elevated"] .block-preview-panel{box-shadow:0 2px 7px rgba(0,0,0,0.5);}
  .block-preview[data-blocks="ruled"] .block-preview-panel{background:transparent;border:none;border-radius:0;padding:0;}
  .block-preview[data-blocks="ruled"] .block-preview-title{border-bottom:1px solid var(--line);padding-bottom:4px;height:10px;width:100%;background:transparent;border-radius:0;}
  .block-preview[data-blocks="compact"] .block-preview-panel{border-radius:3px;padding:4px 5px;gap:3px;}

  .theme-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;}
  @media (max-width:900px){ .theme-grid{grid-template-columns:repeat(2,1fr);} }
  .theme-card{display:flex;flex-direction:column;gap:6px;text-align:left;background:var(--paper-raised);border:1px solid var(--line);border-radius:8px;padding:10px;cursor:pointer;font:inherit;color:inherit;}
  .theme-card:hover{border-color:var(--line-strong);}
  /* 2px so the selected card doesn't shift by a pixel when it becomes selected. */
  .theme-card.selected{border:2px solid var(--sage);padding:9px;}
  .theme-card-name{font-size:13px;font-weight:500;color:var(--ink);}
  .theme-card-tick{color:var(--green-dot);}
  .theme-card-note{font-size:11px;color:var(--text-muted);line-height:1.4;}
  .theme-swatch{display:flex;gap:4px;height:42px;border-radius:5px;border:1px solid var(--line);padding:5px;background:var(--sw-paper);}
  .theme-swatch-rail{width:26px;border-radius:3px;background:var(--sw-rail);}
  .theme-swatch-card{flex:1;border-radius:3px;background:var(--sw-card);border:1px solid var(--sw-line);}
  .theme-swatch[data-theme="grainpath"]{--sw-paper:#DCE1D6;--sw-rail:#2E4A3D;--sw-card:#F7F4EC;--sw-line:#E4DFD3;}
  .theme-swatch[data-theme="garden"]{--sw-paper:#F5F1E8;--sw-rail:#E4E9DF;--sw-card:#FFFFFF;--sw-line:#DAD3C2;}
  .theme-swatch[data-theme="ink"]{--sw-paper:#F4F4F1;--sw-rail:#DEE9E1;--sw-card:#FFFFFF;--sw-line:#DCDCD6;}
  .theme-swatch[data-theme="moss"]{--sw-paper:#EFF2EA;--sw-rail:#D8E7D9;--sw-card:#FDFEFB;--sw-line:#D2DBC9;}
  .theme-swatch[data-theme="slate"]{--sw-paper:#1B1F24;--sw-rail:#26332B;--sw-card:#242A31;--sw-line:#333B45;}
  .theme-swatch[data-theme="dusk"]{--sw-paper:#15161F;--sw-rail:#223026;--sw-card:#1E2029;--sw-line:#2E3040;}
  .theme-swatch[data-theme="ember"]{--sw-paper:#1E1A17;--sw-rail:#2C3527;--sw-card:#292421;--sw-line:#3D3530;}
  .theme-swatch[data-theme="newsprint"]{--sw-paper:#F7F7F5;--sw-rail:#E2E7E2;--sw-card:#FFFFFF;--sw-line:#DEDEDA;}
  .theme-swatch[data-theme="sandstone"]{--sw-paper:#F4EFE6;--sw-rail:#E3E8DC;--sw-card:#FFFCF7;--sw-line:#E2D9CB;}
  .theme-swatch[data-theme="obsidian"]{--sw-paper:#0E0F11;--sw-rail:#1D2A21;--sw-card:#17191C;--sw-line:#282B30;}
  .theme-swatch[data-theme="forest"]{--sw-paper:#101A13;--sw-rail:#213022;--sw-card:#19251C;--sw-line:#2A3A2C;}
  /* Physare keeps the yellow for what is ACTIVE; the group heads are all one
     grey so the rail is not two yellow bars and three grey ones. */
  html[data-theme="physare"] .nav-category-head{--cat-tint:var(--subtle-bg);--cat-ink:var(--ink-soft);--cat-accent:var(--line-strong);}
  html[data-theme="physare"] .nav-category-head.open,html[data-theme="physare"] .nav-category.expanded .nav-category-head{--cat-ink:var(--ink);}
  .theme-swatch[data-theme="physare"]{--sw-paper:#0B0B0C;--sw-rail:#141416;--sw-card:#1A1A1C;--sw-line:#3A3A3E;}

  .nav-category{display:flex;flex-direction:column;}
  /* A group head is a filled band; the tabs inside it are not. That contrast
     is the whole point - the rail carries seven groups and they were reading
     as just more tabs. --cat-tint/--cat-accent are set per group below, so
     this rule never needs to know which colour it is wearing. */
  .nav-category-head{display:flex;justify-content:space-between;align-items:center;padding:7px 10px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.06em;background:var(--cat-tint,transparent);color:var(--cat-ink,var(--text-muted));cursor:pointer;border-radius:var(--radius);transition:box-shadow 0.12s ease;}
  /* Hover draws a ring rather than changing the fill: a second tint per
     family would be seven more tokens in two themes, and the ring reads as
     affordance without shifting the colour somebody just learned. */
  .nav-category-head:hover{box-shadow:inset 0 0 0 1px var(--cat-accent,var(--line-strong));}
  /* Tints are keyed on the GROUP's configured tint (config/platform.php
     nav_groups), one per token family, so a new group picks a family rather
     than editing this file. Text on a tint comes from the same hue. */
  .nav-category-head[data-tint="sage"]{--cat-tint:var(--sage-soft);--cat-ink:var(--sage-ink);--cat-accent:var(--sage);}
  .nav-category-head[data-tint="mustard"]{--cat-tint:var(--mustard-soft);--cat-ink:var(--mustard-ink);--cat-accent:var(--mustard);}
  .nav-category-head[data-tint="blue"]{--cat-tint:var(--blue-soft);--cat-ink:var(--blue-ink);--cat-accent:var(--blue);}
  .nav-category-head[data-tint="violet"]{--cat-tint:var(--violet-soft);--cat-ink:var(--violet-ink);--cat-accent:var(--violet);}
  .nav-category-head[data-tint="brick"]{--cat-tint:var(--brick-soft);--cat-ink:var(--brick-ink);--cat-accent:var(--brick);}
  .nav-category-head[data-tint="plum"]{--cat-tint:var(--plum-soft);--cat-ink:var(--plum-ink);--cat-accent:var(--plum);}
  .nav-category-head[data-tint="teal"]{--cat-tint:var(--teal-soft);--cat-ink:var(--teal-ink);--cat-accent:var(--teal);}
  /* Neutral, not an eighth colour family: Admin is chrome rather than a
     feature area, so reading as grey is apt rather than a compromise. */
  .nav-category-head[data-tint="neutral"]{--cat-tint:var(--subtle-bg);--cat-ink:var(--ink-soft);--cat-accent:var(--line-strong);}
  .nav-caret{transition:transform 0.15s ease;font-size:10px;}
  .nav-caret.open{transform:rotate(90deg);}
  .nav-category-body{display:none;flex-direction:column;gap:2px;}
  .nav-category-body.open{display:flex;}
  @media (max-width:820px){ .nav-category-body.open{flex-direction:row;flex-wrap:wrap;} }

  .dropdown-widget{position:relative;}
  .dropdown-panel{display:none;position:absolute;left:100%;top:0;margin-left:6px;background:var(--paper-raised);border:1px solid var(--line);border-radius:8px;width:320px;max-height:460px;overflow-y:auto;z-index:40;box-shadow:0 4px 14px rgba(31,58,52,0.14);padding:12px;}
  .dropdown-panel.open{display:block;}
  @media (max-width:820px){ .dropdown-panel{left:auto;right:0;top:100%;margin-left:0;margin-top:6px;} }
  .dropdown-panel-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;gap:8px;}
  .dropdown-panel-title{font-family:var(--font-display);font-size:15px;font-weight:600;}

  .rail-foot{font-size:11px;color:var(--text-muted);display:flex;flex-direction:column;gap:10px;}
  @media (max-width:820px){ .rail-foot{display:none;} }
  /* The account button and its menu (2026-10-18). The menu is fixed to the
     screen, placed from the button, so the rail's own scrolling never clips it. */
  .acct-btn{display:flex;align-items:center;gap:10px;width:100%;padding:6px 8px;border:1px solid transparent;border-radius:8px;
    background:transparent;color:var(--ink);font:inherit;font-family:var(--font-ui);text-align:left;cursor:pointer;}
  .acct-btn:hover,.acct-btn[aria-expanded="true"]{background:var(--paper-raised);border-color:var(--line);}
  .acct-av{width:28px;height:28px;flex-shrink:0;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
    background:var(--sage-soft);color:var(--sage-ink, var(--ink));font-size:11px;font-weight:600;letter-spacing:.03em;}
  /* The dark themes define no --sage-ink of their own, so the light one would be dark on dark. */
  html[data-scheme="dark"] .acct-av{color:var(--ink);}
  .acct-name{flex:1;min-width:0;font-size:13px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
  .acct-btn .acct-sel{width:16px;height:16px;color:var(--text-muted);flex-shrink:0;}
  .acct-menu{position:fixed;z-index:60;min-width:204px;padding:4px;background:var(--paper-raised);border:1px solid var(--line);
    border-radius:8px;box-shadow:0 6px 18px rgba(31,58,52,0.16);font-family:var(--font-ui);}
  /* Files on records (platform batch A): one panel every screen hosts. */
  .rf-drop{display:flex;flex-direction:column;align-items:center;gap:4px;border:1.5px dashed var(--line);border-radius:var(--radius);padding:16px;text-align:center;color:var(--ink-soft);font-size:13.5px;background:var(--paper);margin-bottom:12px;cursor:pointer;}
  .rf-drop b{color:var(--ink);}
  .rf-drop.over{border-color:var(--ink);background:var(--subtle-bg);}
  .rf-hint{font-size:12px;}
  .rf-status{font-size:12.5px;color:var(--ink);}
  .rf-status:empty{display:none;}
  .rf-group{font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-soft);margin:14px 0 8px;font-weight:600;}
  .rf-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(176px,1fr));gap:12px;}
  .rf.compact .rf-grid{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px;}
  .rf-card{position:relative;border:1px solid var(--line);border-radius:12px;overflow:hidden;background:var(--paper-raised);}
  .rf-open{display:flex;flex-direction:column;width:100%;padding:0;border:0;background:none;text-align:left;cursor:pointer;color:inherit;font:inherit;}
  .rf-thumb{height:108px;display:flex;align-items:flex-end;justify-content:flex-start;background:var(--subtle-bg) center/cover no-repeat;position:relative;}
  .rf.compact .rf-thumb{height:84px;}
  .rf-thumb.doc{align-items:center;justify-content:center;}
  .rf-ext{margin:8px;font-size:10.5px;background:rgba(0,0,0,.5);color:#fff;padding:2px 6px;border-radius:5px;letter-spacing:.04em;font-weight:600;}
  .rf-ext-big{font-size:20px;font-weight:600;color:var(--ink-soft);letter-spacing:.04em;}
  .rf-meta{display:flex;flex-direction:column;gap:2px;padding:9px 11px;font-size:12.5px;min-width:0;}
  .rf-name{font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
  .rf-sub{color:var(--ink-soft);}
  .rf-on{align-self:flex-start;margin-top:4px;font-size:11.5px;background:var(--subtle-bg);border-radius:6px;padding:1px 6px;color:var(--ink-soft);}
  .rf-del{position:absolute;top:6px;right:6px;min-width:26px;height:26px;padding:0 6px;border-radius:13px;border:1px solid var(--line);background:var(--paper-raised);color:var(--ink-soft);display:flex;align-items:center;justify-content:center;cursor:pointer;font:inherit;font-size:12px;}
  .rf-del .ic{width:14px;height:14px;}
  .rf-del.asking{background:var(--brick);border-color:var(--brick);color:#fff;font-weight:600;}
  .rf-note{font-size:12.5px;color:var(--ink-soft);margin:12px 0 0;}
  @media (max-width: 600px){ .rf-grid, .rf.compact .rf-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;} .rf-thumb, .rf.compact .rf-thumb{height:96px;} .rf-drop .rf-hint{display:none;} }
  .rf-empty{margin:4px 0 0;}
  /* Your calendar in other apps (platform batch C). */
  .cal-link-parts{display:flex;flex-wrap:wrap;gap:6px 18px;}
  .cal-link-url{font-family:var(--font-mono);font-size:12px;background:var(--subtle-bg);border-radius:8px;padding:8px 10px;word-break:break-all;}
  .cal-link-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;}
  .cal-link-tabs{display:flex;gap:6px;flex-wrap:wrap;margin:12px 0 6px;}
  .cal-link-tab{border:1px solid var(--line);background:var(--paper-raised);border-radius:999px;padding:4px 11px;font:inherit;font-size:12.5px;color:var(--ink-soft);cursor:pointer;}
  .cal-link-tab.on{background:var(--ink);color:var(--paper);border-color:var(--ink);}
  .cal-link-steps{margin:4px 0 0;padding-left:18px;font-size:13.5px;line-height:1.7;}
  .install-kinds{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:0 0 14px;}
  .install-kind{border:1px solid var(--line);border-radius:10px;padding:8px 6px;background:var(--paper-raised);color:var(--ink);font:inherit;font-size:13px;cursor:pointer;}
  .install-kind.on{border-color:var(--ink);box-shadow:0 0 0 2px var(--line);font-weight:600;}
  .install-steps{list-style:none;counter-reset:install;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:12px;}
  .install-steps li{counter-increment:install;display:flex;gap:12px;align-items:flex-start;font-size:14px;line-height:1.5;}
  .install-steps li::before{content:counter(install);flex:0 0 26px;height:26px;border-radius:50%;background:var(--ink);color:var(--paper);display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;}
  .install-key{display:inline-flex;align-items:center;gap:4px;border:1px solid var(--line);border-radius:6px;padding:0 6px;background:var(--paper);}
  .install-key .ic{width:14px;height:14px;transform:rotate(180deg);}
  .acct-menu-who{padding:8px 10px 6px;font-size:12px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
  .acct-menu button{display:flex;align-items:center;gap:10px;width:100%;padding:8px 10px;border:0;border-radius:6px;
    background:transparent;color:var(--ink);font:inherit;font-size:13px;text-align:left;cursor:pointer;}
  .acct-menu button:hover,.acct-menu button:focus-visible{background:var(--paper);outline:none;}
  .acct-menu .ic{width:16px;height:16px;color:var(--ink-soft);}
  .acct-menu .acct-out,.acct-menu .acct-out .ic{color:var(--brick);}
  .acct-menu hr{border:0;border-top:1px solid var(--line);margin:4px 2px;}
  .kbd-list{display:grid;grid-template-columns:auto 1fr;gap:10px 16px;align-items:center;margin:4px 0 8px;}
  .kbd-list kbd{font-family:var(--font-mono);font-size:12px;padding:2px 7px;border:1px solid var(--line-strong);border-bottom-width:2px;
    border-radius:5px;background:var(--paper);color:var(--ink);white-space:nowrap;}

  .main{padding:32px 36px 60px;}
  /* The top bar (2026-10-18): search and quick add, right-aligned, on every page. */
  .topbar{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin:-14px 0 18px;}
  /* On a page's own title line (placeTopbar): no margins of its own, a box that gives way first. */
  .page-head > .topbar, .page-head-actions > .topbar{margin:0;flex:0 1 auto;min-width:0;}
  .page-head > .topbar .gs-wrap, .page-head-actions > .topbar .gs-wrap{width:clamp(180px, 24vw, 320px);}
  .page-head-actions > .topbar{margin-right:2px;}
  /* The title takes the free space, so the page's buttons, search and + pack together on the right;
     when the line is too narrow, search wraps to the right-hand end of the next line. */
  .page-head:has(.topbar) > :first-child{flex:1 1 auto;min-width:0;}
  .page-head > .topbar{margin-left:auto;}
  /* Customising the dashboard needs that line for Save, Reset, Cancel and Done. */
  .dashboard-head:has(#dashboard-head-actions > .btn:not(.icon-only)) .topbar{display:none;}
  .topbar .gs-wrap{margin:0;width:min(360px, 100%);}
  .topbar .gs-panel{left:auto;right:0;width:min(520px, 92vw);}
  .topbar-add{width:38px;height:38px;flex-shrink:0;border-radius:50%;border:0;display:inline-flex;align-items:center;justify-content:center;
    background:var(--ink);color:var(--paper-raised);cursor:pointer;}
  .topbar-add:hover{filter:brightness(1.15);}
  .topbar-add .ic{width:18px;height:18px;}
  @media (max-width:820px){ .topbar{margin:0 0 14px;} .topbar .gs-wrap{width:auto;flex:1;} }
  .quick-add-menu{min-width:190px;}
  @media (max-width:820px){ .main{padding:20px 18px 48px;} }

  .page-head{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;margin-bottom:22px;flex-wrap:wrap;}
  .page-title{font-family:var(--font-display);font-size:28px;font-weight:600;margin:0;}
  .page-sub{font-size:13px;color:var(--ink-soft);margin:4px 0 0;}
  .back-link{font-size:12px;color:var(--ink-soft);cursor:pointer;display:inline-flex;align-items:center;gap:4px;margin-bottom:10px;}
  .back-link:hover{color:var(--ink);}
  /* A record's top row (Nick, 2026-10-19): a round back button, the title, and
     the search and + in the same row through a .topbar-slot, so the search no
     longer takes a row of its own above the page. */
  .detail-top{display:flex;align-items:center;gap:14px;min-height:48px;margin:0 0 18px;}
  .detail-top-title{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0;}
  .detail-top-title .page-title{margin:0;line-height:1.15;overflow-wrap:anywhere;}
  .detail-top > .topbar{margin:0 0 0 auto;flex:0 1 auto;min-width:0;}
  .detail-top > .topbar .gs-wrap{width:clamp(180px, 22vw, 300px);}
  .back-btn{flex:none;width:44px;height:44px;border-radius:50%;border:1px solid var(--line-strong);background:var(--paper-raised);color:var(--ink);
    display:grid;place-items:center;cursor:pointer;padding:0;box-shadow:0 1px 2px rgba(0,0,0,.05);}
  .back-btn:hover{background:var(--subtle-bg);}
  .back-btn .ic{width:20px;height:20px;}
  /* The record's own line under the top row: what it is on the left, its actions on the right. */
  .page-head.detail-head{margin-top:-6px;}
  .page-head.detail-head .page-sub{margin-top:0;}
  /* A record opened inside its tab (a return, a stock count) sits under the tab's own
     title and search, so it takes a smaller round button beside its heading instead. */
  .back-btn.sm{width:36px;height:36px;}
  .back-btn.sm .ic{width:17px;height:17px;}
  .detail-section-title{display:flex;align-items:center;gap:12px;min-width:0;}

  .btn{font-family:var(--font-ui);font-size:13px;font-weight:500;padding:9px 16px;border-radius:var(--radius);border:1px solid var(--ink);background:var(--ink);color:var(--paper);cursor:pointer;}
  .btn:hover{background:var(--ink-soft);}
  .btn.ghost{background:transparent;color:var(--ink);border-color:var(--line-strong);}
  .btn.ghost:hover{background:var(--paper-raised);}
  .btn.danger{background:transparent;color:var(--brick);border-color:var(--brick);}
  .btn.danger:hover{background:var(--brick-soft);}
  .btn.small{padding:5px 10px;font-size:12px;}
  .btn:disabled{opacity:0.4;cursor:default;}

  .collapse-toggle{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border-radius:var(--radius);border:1px solid var(--line-strong);background:transparent;color:var(--ink);cursor:pointer;}
  .collapse-toggle:hover{background:var(--paper-raised);}
  .collapse-arrow{display:inline-block;font-size:13px;line-height:1;transition:transform .15s ease;transform:rotate(-90deg);}
  .collapse-arrow.expanded{transform:rotate(0deg);}

  .toolbar{display:flex;gap:10px;align-items:center;margin:16px 0 18px;flex-wrap:wrap;}
  input[type=text], input[type=email], input[type=password], input[type=tel], input[type=date], input[type=time], input[type=number], input[type=url], textarea, select{
    font-family:var(--font-ui);font-size:13px;padding:8px 10px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--paper-raised);color:var(--ink);
  }
  textarea{font-family:var(--font-ui);resize:vertical;}
  input:focus, textarea:focus, select:focus{outline:none;border-color:var(--mustard);box-shadow:0 0 0 2px var(--mustard-soft);}
  input.search{
    flex:1;min-width:180px;padding-right:32px;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23808080' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E");
    background-repeat:no-repeat;background-position:right 10px center;background-size:16px 16px;
  }

  .price-wrap{display:flex;align-items:center;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--paper-raised);padding:0 8px;}
  .price-wrap span{color:var(--ink-soft);font-size:13px;}
  .price-wrap input{border:none;background:transparent;padding:8px 4px;width:100%;-webkit-appearance:none;appearance:none;}
  .price-wrap input:focus{outline:none;box-shadow:none;border:none;}
  .price-wrap:focus-within{border-color:var(--mustard);box-shadow:0 0 0 2px var(--mustard-soft);}
  .price-wrap input::-webkit-inner-spin-button, .price-wrap input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0;}
  .price-wrap input[type=number]{-moz-appearance:textfield;}

  .modal-header-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:18px;gap:12px;flex-wrap:wrap;}
  .modal-header-row h2{margin:0;}
  .inline-checkbox{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:500;cursor:pointer;white-space:nowrap;}
  .inline-checkbox input{width:16px;height:16px;padding:0;}
  /* A bare class does NOT beat `.field label` / `.field input` (both 0,1,1),
     and those come LATER in this file, so inside any .field the label stayed
     display:block and the checkbox stretched to width:100% - rendering as a
     full-width box ABOVE its own text, which is why it appeared to land in
     the middle of a word. Broken in every .field since it shipped. The
     descendant selector is (0,2,1) and names every property the generic
     rules set, since whichever is missed keeps leaking through. Same trap
     the .gs-box .gs-input rule documents. */
  .field .inline-checkbox{display:flex;align-items:center;gap:6px;margin-bottom:0;
    font-size:13px;color:var(--ink);font-weight:500;cursor:pointer;white-space:nowrap;}
  .field .inline-checkbox input{width:16px;height:16px;padding:0;margin:0;}
  .checkbox-group{display:flex;gap:14px;flex-wrap:wrap;}


  .panel{background:var(--panel-bg);border:var(--panel-border);border-radius:var(--panel-radius);padding:var(--panel-pad);box-shadow:var(--panel-shadow);}
  .card-list{display:flex;flex-direction:column;border:var(--panel-border);border-radius:var(--panel-radius);overflow:hidden;background:var(--panel-bg);box-shadow:var(--panel-shadow);}
  .row{display:grid;gap:12px;align-items:center;padding:var(--row-pad);border-bottom:1px solid var(--line);cursor:pointer;}
  .row:last-child{border-bottom:none;}
  .row:hover{background:var(--subtle-bg);}
  .row.head{font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:0.06em;color:var(--text-muted);cursor:default;}
  .row.head:hover{background:transparent;}
  .row.head .sortable{cursor:pointer;user-select:none;}
  .row.head .sortable:hover{color:var(--ink);}
  /* Every fraction is minmax(0,...) because each .row is its own grid
     container, so a bare fr floors at that row's min-content width and a long
     company name resolves its columns differently from its neighbours. */

  /* A toolbar button is a TAP TARGET on a phone, and .btn.small renders 25px
     high, under the 30px floor the mobile navigation had to learn the hard
     way. Scoped to .toolbar rather than every .btn.small: the ones inside
     table rows are fine as they are, and growing those would make every row
     taller. Week navigation and Day/Week toggles are what somebody actually
     presses repeatedly with a thumb. */
  @media (max-width:760px){
    /*
     * The 30px floor, and it was scoped to TOOLBARS only.
     *
     * `.btn.small` renders 25px, and the buttons inside a list row are the
     * most-pressed controls on a phone: Mark delivered, Generate invoice and
     * Mark paid all sat under the floor the toolbar buttons were raised to.
     * Extended to the action cells, which is where the thumb actually goes.
     *
     * Still NOT every .btn.small - the ones inside dense table rows stay as
     * they are, because growing those makes every row taller and the standing
     * decision there was that a mouse target is fine at that size.
     */
    .toolbar .btn.small,.toolbar .seg button,
    .row .order-actions .btn.small,.order-actions .btn.small{min-height:32px;padding-top:7px;padding-bottom:7px;}
  }


  .primary-text{font-weight:500;}
  .sub-text{color:var(--ink-soft);font-size:13px;}
  .micro-text{color:var(--text-muted);font-size:11px;}
  .empty{padding:40px 20px;text-align:center;color:var(--ink-soft);}
  .empty h3{font-family:var(--font-display);font-size:19px;margin:0 0 6px;color:var(--ink);}
  .empty p{font-size:13px;margin:0 0 16px;}

  /* nowrap because a status label broken across two lines reads as two
     words rather than one state, and it makes its row taller than its
     neighbours, which is what makes a list look broken. */
  .badge{display:inline-block;font-size:11px;font-weight:500;padding:3px 9px;border-radius:20px;white-space:nowrap;}
  .badge.pending{background:var(--mustard-soft);color:#8A5A1E;}
  .badge.fulfilled{background:var(--sage-soft);color:#3E5340;}
  .badge.paid{background:var(--green-dot);color:#12281A;}
  .badge.consigned{background:var(--blue-soft);color:#2E5570;}
  /* Where a record moves through stages, in the same tinted language as the
     badges above: soft ground, text from the SAME hue. Deliberately generic
     rather than one family per feature, because several list screens
     ask the same four questions and two copies of these tints would
     drift. Waiting shares Pending's mustard; progress takes blue, the only
     family here that reads as movement rather than warning or success; and
     muted covers every way a record stops being live. */
  .badge.st-waiting{background:var(--mustard-soft);color:#8A5A1E;}
  .badge.st-progress{background:var(--blue-soft);color:#2E5570;}
  .badge.st-done{background:var(--sage-soft);color:#3E5340;}
  .badge.st-muted{background:var(--subtle-bg);color:var(--text-muted);}
  .badge.customer-created{background:var(--mustard-soft);color:#7A4E13;}
  .badge.sentiment-not{background:var(--brick-soft);color:#8C332E;}
  .badge.sentiment-follow{background:var(--blue-soft);color:#2E5570;}
  .company-tag-pill{position:relative;padding-right:16px;}
  .company-tag-remove{display:none;position:absolute;right:4px;top:50%;transform:translateY(-50%);cursor:pointer;font-weight:600;line-height:1;}
  .company-tag-pill:hover .company-tag-remove{display:inline;}
  .company-tag-pill:hover{padding-right:20px;}
  .badge.sentiment-nurture{background:var(--sage-soft);color:#3E5340;}
  .badge.sentiment-connected{background:var(--green-dot);color:#12281A;}
  .badge.warn{background:var(--brick-soft);color:#8C332E;}
  .badge.neutral{background:var(--subtle-bg);color:var(--text-muted);box-shadow:inset 0 0 0 1px var(--line);}
  .icon-chip{display:inline-flex;align-items:center;gap:5px;font-size:12px;color:var(--ink-soft);}

  .dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:9px;flex-shrink:0;}
  .dot.customer{background:var(--green-dot);}
  .dot.prospect{background:var(--yellow-dot);}
  .dot.lead{background:var(--blue);}
  .dot.inv-paid{background:var(--green-dot);}
  .dot.inv-unpaid{background:var(--yellow-dot);}
  .dot.inv-overdue{background:var(--brick);}
  .dot.inv-voided{background:var(--text-muted);}
  /* Paid but not yet cleared - distinct from both paid and unpaid, because it
     is genuinely neither. */
  .dot.inv-processing{background:var(--sage);}
  .name-with-dot{display:flex;align-items:center;}

  .section{margin-top:30px;}
  /*
   * The dashboard is a TWELVE COLUMN GRID, not a stack.
   *
   * Every panel was full width and most were mostly empty: Sales used about
   * 300px of a 1100px panel and Invoices about 340px. A panel is now only as
   * wide as its contents need, and Sales sits beside Invoices.
   *
   * `gap` replaces the old margin-top, so a panel carries no spacing of its
   * own and the grid owns the rhythm. A panel that kept its own margin would
   * push its whole row down and break the alignment.
   */
  .dashboard-grid{ display:grid; grid-template-columns:repeat(12,minmax(0,1fr)); gap:18px; align-items:stretch; }
  .dashboard-section{background:var(--paper-raised);border:1px solid var(--line);border-radius:10px;padding:20px 22px;grid-column:span 12;}

  /*
   * align-items:STRETCH, so panels sharing a row match heights.
   *
   * The first version used `start`, on the reasoning that a panel saying
   * "nothing due" should be one line tall rather than as tall as the table
   * beside it. That was wrong on a grid: ragged bottoms read as broken, where
   * an even row reads as deliberate. The cost is honest -- a short panel now
   * carries empty space -- and it is the better trade at this width.
   */

  /*
   * A column of two short panels beside a tall one.
   *
   * The last child grows, so the stack ends flush with the panel beside it
   * rather than leaving the hole at the bottom that stretching one panel was
   * meant to solve. It is a grid CHILD, so it takes the same data-span rules
   * as a panel and needs no width logic of its own.
   */
  .dashboard-stack{ display:flex; flex-direction:column; gap:18px; grid-column:span 12; min-width:0; }
  .dashboard-stack > .dashboard-section:last-child{ flex:1; }

  /*
   * Customize mode. Each panel gets a control bar (drag handle, arrows, its
   * name, size, hide) and its own contents go inert, so a click meant for a
   * control never opens a record. The handle carries touch-action:none, or
   * a finger dragging it would scroll the page instead.
   */
  .dashboard-grid.is-editing > .dashboard-section{ border:1.5px dashed var(--line-strong); }
  .dashboard-grid.is-editing .dash-panel-body{ pointer-events:none; opacity:.72; }
  /* Drag and drop: the whole panel is the grip, a lifted copy follows the
     pointer, and a dashed gap marks where it will land. */
  .dashboard-grid.is-editing > .dashboard-section{ cursor:grab; user-select:none; }
  .dashboard-section.is-placeholder{ border:2px dashed var(--ink-soft) !important; background:transparent; box-shadow:none; }
  .dashboard-section.is-placeholder > *{ visibility:hidden; }
  .dashboard-section.is-placeholder.is-new{ min-height:96px; }
  .dash-ghost{ position:fixed; left:0; top:0; z-index:1000; pointer-events:none; margin:0; overflow:hidden;
    box-shadow:0 18px 40px rgba(0,0,0,.28); opacity:.94; border-radius:10px; }
  .dash-ghost.dash-tray-chip{ background:var(--paper-raised); }
  body.dash-dragging, body.dash-dragging *{ cursor:grabbing !important; user-select:none; }
  #dashboard-tray.is-drop-target .dash-tray{ border:2px dashed var(--brick); background:var(--brick-soft); }
  .dash-tray-hint{ margin-left:8px; color:var(--text-muted); font-size:11px; }
  .dash-tray-chip{ cursor:grab; touch-action:none; }
  .dash-controls{ display:flex; align-items:center; gap:6px; margin:-8px -8px 12px; padding:6px 8px;
    border-radius:8px; background:var(--paper); font-size:12px; color:var(--ink-soft); }
  .dash-controls button{ font:inherit; font-size:12px; color:var(--ink); background:transparent; border:1px solid var(--line-strong);
    border-radius:6px; padding:3px 7px; cursor:pointer; line-height:1.2; }
  .dash-controls button:hover{ background:var(--paper-raised); }
  .dash-handle{ cursor:grab; touch-action:none; }
  .dash-handle:active{ cursor:grabbing; }
  .dash-title{ font-weight:600; color:var(--ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .dash-sizes{ display:inline-flex; margin-left:auto; }
  .dash-sizes button{ border-radius:0; margin-left:-1px; }
  .dash-sizes button:first-child{ border-radius:6px 0 0 6px; margin-left:0; }
  .dash-sizes button:last-child{ border-radius:0 6px 6px 0; }
  .dash-sizes button.on{ background:var(--ink); border-color:var(--ink); color:var(--paper); }
  .dash-hide{ margin-left:4px; }
  .dash-controls .dash-hide:only-of-type{ margin-left:auto; }
  .dash-arrow{ display:none; }
  .dash-tray{ margin-top:18px; padding:14px 16px; border:1px solid var(--line); border-radius:10px; background:var(--paper-raised); }
  .dash-tray-head{ font-size:12px; color:var(--ink-soft); margin-bottom:10px; }
  .dash-tray-chip{ font:inherit; font-size:13px; padding:6px 12px; margin:0 6px 6px 0; border-radius:20px;
    border:1px solid var(--line-strong); background:transparent; color:var(--ink); cursor:pointer; }
  .dash-tray-chip:hover{ background:var(--paper); }
  /* A count tile: one number, the whole panel a button to the list behind it. */
  .dash-tile{ display:flex; flex-direction:column; align-items:flex-start; gap:4px; width:100%; font:inherit; color:inherit;
    background:none; border:none; padding:0; text-align:left; cursor:pointer; }
  /* A tile keeps its own height beside a tall panel rather than stretching to match it. */
  .dashboard-section.is-tile{ padding:16px 20px; align-self:start; }
  /*
   * A customised dashboard is a grid of ROWS as well as columns: 22px tracks
   * plus the 18px gap make a 40px step, a panel spans the rows its height
   * says, and `dense` lets a short panel move up into a hole. A panel sized
   * by hand scrolls inside itself; one left to fit grows to its content.
   */
  .dashboard-grid.is-free{ grid-auto-rows:22px; grid-auto-flow:row dense; }
  .dashboard-grid.is-free > .dashboard-section{ position:relative; display:flex; flex-direction:column; min-width:0; overflow:hidden; align-self:stretch; }
  .dashboard-grid.is-free > .dashboard-section > .dash-panel-body{ flex:1 1 auto; min-height:0; overflow:auto; }
  .dashboard-grid.is-free > .dashboard-section.is-fit > .dash-panel-body{ flex:none; overflow:visible; }
  .dashboard-grid.is-free > .dashboard-section.is-tile{ align-self:stretch; }

  /* The grips: the right edge, the bottom edge and the corner, each a thin bar that darkens on hover. */
  .dash-grip{ position:absolute; z-index:3; touch-action:none; }
  .dash-grip-r{ top:0; right:0; width:12px; height:100%; cursor:ew-resize; }
  .dash-grip-b{ left:0; bottom:0; height:12px; width:100%; cursor:ns-resize; }
  .dash-grip-c{ right:0; bottom:0; width:20px; height:20px; cursor:nwse-resize; z-index:4; }
  .dash-grip-r::after{ content:''; position:absolute; top:50%; right:3px; width:4px; height:40px; margin-top:-20px; border-radius:3px; background:var(--line-strong); }
  .dash-grip-b::after{ content:''; position:absolute; left:50%; bottom:3px; height:4px; width:40px; margin-left:-20px; border-radius:3px; background:var(--line-strong); }
  .dash-grip-c::after{ content:''; position:absolute; right:4px; bottom:4px; width:9px; height:9px; border-right:2px solid var(--ink-soft); border-bottom:2px solid var(--ink-soft); border-bottom-right-radius:3px; }
  .dash-grip:hover::after, .dashboard-section.is-resizing .dash-grip::after{ background:var(--ink); }
  .dash-grip-c:hover::after{ background:none; border-color:var(--ink); }
  .dashboard-section.is-resizing{ border-color:var(--ink) !important; }
  .dash-size-tag{ position:absolute; right:14px; bottom:18px; z-index:5; pointer-events:none; background:var(--ink); color:var(--paper);
    font-size:12px; padding:4px 9px; border-radius:6px; white-space:nowrap; }
  .dash-size-readout{ margin-left:auto; font-size:11px; color:var(--ink-soft); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  body.dash-resizing, body.dash-resizing *{ user-select:none; }
  body.dash-resizing-r, body.dash-resizing-r *{ cursor:ew-resize !important; }
  body.dash-resizing-b, body.dash-resizing-b *{ cursor:ns-resize !important; }
  body.dash-resizing-c, body.dash-resizing-c *{ cursor:nwse-resize !important; }
  /* One column on a phone: width is always the whole row, so only the bottom grip remains. */
  @media (max-width:759px){
    .dashboard-grid.is-free > .dashboard-section{ grid-column:1 / -1 !important; }
    .dash-grip-r, .dash-grip-c, .dash-size-readout{ display:none; }
  }
  /* On a phone the arrows replace the handle: dragging inside a long scrolling page is fiddly. */
  @media (max-width:759px){
    .dash-handle{ display:none; }
    .dash-arrow{ display:inline-block; }
    .dash-controls button{ min-height:34px; min-width:34px; }
    .dash-sizes{ display:none; }
    .dash-controls .dash-hide{ margin-left:auto; }
  }

  /*
   * Inside the stack, metric cards are pinned to TWO columns rather than left
   * to auto-fit.
   *
   * The stack column is about 296px at 1250px wide, so auto-fit's 140px
   * minimum plus the gap does not fit two and drops to one -- which put On
   * hand above Consignment at exactly the width where the row had space for
   * them side by side. The panel always carries two cards, so the count is
   * known and worth stating rather than inferring from arithmetic that changes
   * with the viewport.
   *
   * Above the mobile breakpoint only: at 375px two columns would be about
   * 130px each, which is narrower than the figures want.
   */
  @media (min-width:760px){
    .dashboard-stack .metric-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  }

  @media (min-width:1100px){
    .dashboard-stack[data-span="4"]{ grid-column:span 4; }
    .dashboard-section[data-span="4"]{ grid-column:span 4; }
    .dashboard-section[data-span="6"]{ grid-column:span 6; }
    .dashboard-section[data-span="8"]{ grid-column:span 8; }
  }

  /*
   * The middle band, 760 to 1100: the halves pair up but the thirds do not,
   * because a third of a 900px page is about 240px and narrower than three
   * metric cards can sit in. Reading order survives either way, since the grid
   * places in source order.
   *
   * `data-mid-span` is how a panel says it needs the whole row HERE and not at
   * full width. Two do: Production needed, whose eight of twelve leaves a
   * four-wide remainder nothing else can fill, and Marketing, the odd one out
   * among five half-width panels -- five can never pair evenly, so exactly one
   * has to go wide. Without it Marketing sat alone with 306px beside it.
   */
  @media (min-width:760px) and (max-width:1099px){
    .dashboard-section[data-span="4"],
    .dashboard-stack[data-span="4"],
    .dashboard-section[data-span="6"]{ grid-column:span 6; }

    .dashboard-section[data-mid-span="12"],
    .dashboard-stack[data-mid-span="12"]{ grid-column:span 12; }
  }

  /* One line under a rule, rather than a row of filled pills.
     Two pills plus a trailing sentence read as three unrelated fragments; a
     severity dot, a count and a label scan left to right as one list. The rule
     is what separates it from the grid below without needing a card. */
  .alerts-strip{display:flex;align-items:center;gap:18px;flex-wrap:wrap;
    margin-bottom:20px;padding-bottom:12px;border-bottom:1px solid var(--line);}
  .alert-item{display:inline-flex;align-items:center;gap:7px;border:0;background:transparent;
    font:inherit;font-size:13px;color:var(--ink-soft);cursor:pointer;padding:0;}
  .alert-item:hover{color:var(--ink);}
  /* The dot carries the severity, so the label keeps the page's own text
     colour and the line reads as prose rather than as a warning banner. */
  .alert-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;}
  .alert-item.overdue .alert-dot{background:var(--brick);}
  .alert-item.pending .alert-dot{background:var(--mustard);}
  .alert-item .alert-count{font-family:var(--font-display);font-weight:600;font-size:14px;color:var(--ink);}
  .alert-item.overdue .alert-count{color:var(--brick);}
  .alert-item.pending .alert-count{color:var(--mustard);}
  .alert-pill{display:flex;align-items:center;gap:7px;background:var(--paper-raised);border:1px solid var(--line);border-radius:20px;padding:7px 14px;font-size:12px;color:var(--ink-soft);cursor:pointer;}
  .alert-pill:hover{border-color:var(--line-strong);}
  .alert-pill .alert-count{font-family:var(--font-display);font-weight:600;font-size:14px;color:var(--ink);}
  .alert-pill.warn{border-color:var(--brick);}
  .alert-pill.warn .alert-count{color:var(--brick);}
  /* Stated rather than merely absent: an empty strip reads as a failed load.
     Pushed to the end of the line, because what is clear is the least urgent
     thing on it and should not sit between two things that are not. */
  .alerts-clear{display:flex;align-items:center;font-size:12px;color:var(--text-muted);margin-left:auto;}


  .section-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;}
  .section-title{font-family:var(--font-display);font-size:18px;font-weight:600;margin:0;}

  /*
   * 140px, not 160.
   *
   * A half-width panel gives the grid about 497px, and three columns at 160
   * need 504 -- seven pixels short, so a three-card panel wrapped 2-then-1 and
   * orphaned the third card beside a hole. That only appeared once the
   * dashboard went to two columns: at full width there was always room.
   *
   * 140 was measured rather than guessed: three fit in 444, and the longest
   * label in use ("Accounts receivable") still sits on one line.
   */
  .metric-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;margin-top:16px;}
  .metric-card{background:var(--paper-raised);border:1px solid var(--line);border-radius:8px;padding:14px 16px;}
  .metric-card.clickable{cursor:pointer;}
  .metric-card.clickable:hover{border-color:var(--line-strong);}
  .metric-label{font-size:12px;color:var(--ink-soft);display:flex;justify-content:space-between;align-items:center;gap:6px;}
  .metric-value{font-family:var(--font-display);font-size:22px;font-weight:600;margin-top:2px;}
  /* Ageing bands for the Receivables report belong to a reports module; not carried. */

  .metric-value.warn{color:var(--brick);}


  table.data{width:100%;border-collapse:collapse;background:var(--paper-raised);border:1px solid var(--line);border-radius:8px;overflow:hidden;font-size:13px;}
  table.data th{text-align:left;font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:0.05em;color:var(--text-muted);font-weight:400;padding:9px 12px;border-bottom:1px solid var(--line);}
  table.data td{padding:9px 12px;border-bottom:1px solid var(--line);}
  table.data tr:last-child td{border-bottom:none;}
  table.data tr:hover td{background:var(--subtle-bg);}

  .filter-menu{position:relative;}
  /* Capped and scrollable: the companies panel carries eleven controls, and an
     uncapped one runs off the bottom of a laptop screen with the Clear button
     on the part nobody can reach. */
  .filter-menu-panel{display:none;position:absolute;top:100%;right:0;margin-top:6px;background:var(--paper-raised);border:1px solid var(--line);border-radius:8px;box-shadow:0 4px 10px rgba(0,0,0,0.1);z-index:60;padding:12px;min-width:272px;max-width:300px;max-height:min(70vh,560px);overflow-y:auto;flex-direction:column;gap:2px;}
  /* Grouped rather than one unbroken column of fields: the headings are what
     let somebody find "how many sites" without reading every label. */
  .filter-section{display:flex;flex-direction:column;gap:7px;padding:9px 0;border-bottom:1px solid var(--line);}
  .filter-section:last-of-type{border-bottom:none;}
  .filter-section:first-of-type{padding-top:2px;}
  .filter-section-head{font-size:10px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-soft);opacity:.75;}
  .filter-section .field{margin:0;gap:3px;}
  .filter-section .field label{font-size:11px;}
  .filter-section .sub-text{font-size:11px;line-height:1.35;}
  /* A min/max pair on one line. Two stacked full-width fields for what is
     obviously one range is what made the old panel need scrolling. */
  .filter-range{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:center;gap:5px;}
  .filter-range-input{width:100%;min-width:0;font-size:12px;padding:5px 7px;}
  .filter-range-sep{font-size:10px;color:var(--ink-soft);opacity:.7;}
  /* Segmented control. Replaces the "Show archived instead" checkbox, which sat
     alone above a column of dropdowns and read as an afterthought. Active and
     Archived are two views of one list, and a two-state control says that where
     a lone checkbox does not. */
  .seg{display:flex;border:1px solid var(--line);border-radius:6px;overflow:hidden;background:var(--paper);}
  .seg button{flex:1 1 0;min-width:0;border:none;background:transparent;color:var(--ink-soft);
    font-size:11px;font-weight:600;padding:5px 6px;cursor:pointer;white-space:nowrap;
    border-right:1px solid var(--line);font-family:inherit;}
  .seg button:last-child{border-right:none;}
  /* `.seg button` is flex:1 1 0 with white-space:nowrap, so a label longer than
     its share of the row overflows the button rather than wrapping: "Email
     campaigns" was clipped mid-word. Where the labels are words rather than a
     two-state toggle, the buttons size to content instead. The
     `.auto-group-head .seg` precedent, and the reason that rule exists too. */
  /* The buttons hug their labels, so the CONTAINER has to as well: `.seg` is
     display:flex, which is block-level and fills its parent, leaving a long
     empty box trailing off to the right of the last button. Only bites where
     a seg is a direct child of the page; the three inside a `.section-head`
     are flex items already, and a flex item's inline-flex is blockified, so
     this leaves them exactly as they were. */
  .seg.seg-auto{display:inline-flex;}
  .seg.seg-auto button{flex:0 0 auto;}
  .seg button:hover{background:var(--paper-raised);color:var(--ink);}
  .seg button.active{background:var(--sage-soft);color:var(--sage-ink);}
  .filter-menu-badge{display:inline-block;background:var(--blue);color:#fff;border-radius:10px;font-size:11px;line-height:1;padding:2px 6px;margin-left:4px;}
  .filter-menu-actions{border-top:1px solid var(--line);padding-top:8px;margin-top:2px;}

  .combo{position:relative;}
  .combo-control{position:relative;}
  /* The right padding has to clear the magnifier and chevron sitting on top
     of the input, and it must be written as a DESCENDANT selector.

     `.combo-input` alone is (0,1,0) and the generic
     `input[type=text], …` control rule is (0,1,1), so that rule's `padding`
     SHORTHAND won and the 56px was silently discarded: every combobox in
     the app had 10px of right padding, and any label long enough to fill
     the field ran underneath the icons. Reported on a quote's service line
     as "Custom Mold Fee (Unit, flat rat" with the chevron sitting in the
     text. The FOURTH time this trap has bitten, after .sp-thumb,
     .gs-box .gs-input and .field .inline-checkbox.

     The whole padding is named rather than just the right side, so the
     shorthand cannot come back and reset the other three. */
  .combo-control .combo-input{width:100%;padding:8px 56px 8px 10px;}
  .combo-icons{position:absolute;right:8px;top:50%;transform:translateY(-50%);display:flex;gap:4px;color:var(--ink-soft);cursor:pointer;}
  .combo-panel{display:none;position:absolute;top:100%;left:0;right:0;margin-top:4px;background:var(--paper-raised);border:1px solid var(--line);border-radius:8px;box-shadow:0 4px 10px rgba(0,0,0,0.1);z-index:70;max-height:160px;overflow-y:auto;}
  .combo-option{padding:8px 10px;font-size:13px;cursor:pointer;}
  .combo-option:hover{background:var(--sage-soft);}
  .combo-group-label{padding:6px 10px 2px;font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);font-family:var(--font-mono);}
/* A team heading that is ALSO a choice, with its people indented under it.
   Weight is what separates the two, not the indent alone: a person and a team
   must never read as the same kind of thing. */
.combo-option.combo-opt-team{font-weight:600;}
.combo-option.combo-opt-member{padding-left:26px;}
/* Kept on screen only because one of its people matched the search. */
.combo-option.combo-opt-context{color:var(--text-muted);font-weight:500;}
/* Heads the people on no team. Not a thing work can be assigned to. */
.combo-option.combo-opt-label{color:var(--text-muted);cursor:default;}
.combo-option.combo-opt-label:hover{background:transparent;}
  /* Checkbox filter dropdown: several real filters are "any of several"
     (Nick's or Sara's, overdue or due soon), which a single <select> can only
     ever express one answer to. */
  /* Multi-select filter. The control itself is a real .combo (same input, same
     magnifier and chevron), so it reads as the control people already know from
     every single-select filter; only the panel differs, carrying checkboxes. */
  .fms{position:relative;}
  /* EVERY rule here is scoped under .fms - a bare .fms-option (0,1,0) LOSES to
     the global `.field label` (0,1,1), which sets display:block and a bottom
     margin. That is exactly what broke the first version: the checkbox and its
     text stacked with a gap between every row. */
  .fms .fms-panel{display:none;position:absolute;top:100%;left:0;right:0;margin-top:4px;
    background:var(--paper-raised);border:1px solid var(--line);border-radius:8px;
    box-shadow:0 4px 10px rgba(0,0,0,0.1);z-index:70;max-height:220px;overflow-y:auto;padding:4px;}
  .fms label.fms-option{display:flex;align-items:center;gap:8px;margin:0;padding:6px 8px;
    font-size:12px;font-weight:400;color:var(--ink);cursor:pointer;border-radius:5px;line-height:1.3;}
  .fms label.fms-option:hover{background:var(--sage-soft);}
  .fms label.fms-option input[type="checkbox"]{margin:0;flex:0 0 auto;width:14px;height:14px;
    accent-color:var(--sage-ink);cursor:pointer;}
  .fms .fms-option-label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  .combo-empty{padding:10px;font-size:12px;color:var(--ink-soft);}
  .combo-disabled .combo-control .combo-input{background:var(--subtle-bg);color:var(--text-muted);cursor:not-allowed;}
  .combo-disabled .combo-icons{cursor:not-allowed;opacity:0.5;}


  .overlay{position:fixed;inset:0;background:rgba(31,58,52,0.35);display:flex;align-items:flex-start;justify-content:center;padding:40px 16px;overflow-y:auto;z-index:100;}
  .modal{background:var(--paper-raised);border-radius:10px;padding:24px 26px;width:100%;max-width:560px;border:1px solid var(--line);}
  .modal h2{font-family:var(--font-display);font-size:20px;margin:0 0 18px;font-weight:600;}
  .field{margin-bottom:14px;position:relative;}
  .field label{display:block;font-size:12px;color:var(--ink-soft);margin-bottom:5px;font-weight:500;}
  .field input, .field textarea, .field select{width:100%;}
  .field-row{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
  .field-row.three{grid-template-columns:1fr 1fr 1fr;}


  /* ---------- wide desktop forms ---------- */
  /*
   * Editing a company meant scrolling a long single column inside a 560px box
   * on a 1920px screen. **Width alone fixes nothing**: measured, the company
   * form's 15 fields are 1197px tall at 560px AND at 900px, because a stacked
   * column is a stacked column. Pairing is what removes the scroll (1197 ->
   * 801, which fits the ~820px a 900px-tall laptop gives); width is only what
   * makes pairing possible.
   *
   * Mobile-first, the `.auto-builder` precedent: ONE column below 900px, so
   * this work is provably inert on a phone. That is deliberate rather than
   * cautious - at 375px an existing `.field-row.three` already renders 89px
   * fields, so anything pairing more on a phone would make it worse.
   */
  .modal.wide{max-width:960px;}
  .modal.medium{max-width:760px;}
  .modal.narrow{max-width:440px;}

  /* Pop-ups (Nick, 2026-10-19): centred in the window when they fit. A taller
     one starts at the top and the overlay scrolls, its buttons held at the
     bottom of the window: sticky inside the scrolling overlay rather than an
     inner scroll box, which would clip a dropdown opened near the bottom. The
     button that does the job is on the right, everything else on the left. */
  .overlay{align-items:flex-start;padding:24px 16px;}
  .modal{margin:auto 0;}
  .modal > .modal-actions{position:sticky;bottom:-24px;z-index:2;margin:20px -26px -24px;padding:14px 26px 18px;border-radius:0 0 10px 10px;}
  /* Solid only on a pop-up taller than the window (is-tall, syncModalDialogs),
     where it covers the fields scrolling beneath it; otherwise see-through, so
     it never slices across the pop-up's own background. */
  .modal.is-tall > .modal-actions{background:var(--paper-raised);box-shadow:0 -1px 0 var(--line);}
  .modal-actions > .btn:last-child{margin-left:auto;}
  .modal .app-loading{min-height:260px;}

  /* Number boxes (Nick's choice B, 2026-10-19): a minus and a plus inside the
     box around the figure (installNumberSteppers). The browser's own arrows
     are hidden everywhere, on the plain money and rate boxes too. */
  input[type=number]{-moz-appearance:textfield;appearance:textfield;}
  input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0;}
  .num-step{display:flex;align-items:center;gap:2px;width:100%;min-width:0;min-height:34px;box-sizing:border-box;padding:0 3px;
    border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--paper-raised);}
  .num-step:focus-within{border-color:var(--mustard);box-shadow:0 0 0 2px var(--mustard-soft);}
  .num-step > input[type=number]{flex:1 1 auto;min-width:0;width:auto !important;max-width:none !important;height:auto !important;
    border:0 !important;background:transparent !important;box-shadow:none !important;padding:4px 2px !important;text-align:center;}
  .num-step-btn{flex:none;width:26px;height:26px;padding:0;border:0;border-radius:calc(var(--radius) - 1px);background:var(--subtle-bg);color:var(--ink);
    display:grid;place-items:center;cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent;}
  .num-step-btn:hover{background:var(--line);}
  .num-step-btn:disabled{opacity:.4;cursor:default;}
  .num-step-btn .ic{width:14px;height:14px;}
  .modal:focus{outline:none;}
  /* Nothing in a pop-up wider than its box (the audit found Qty and Price
     poking past the edge on a phone). */
  .modal .field-row > *{min-width:0;}
  .modal .field input, .modal .field select{max-width:100%;}

  /* A priced line, a quote's or a job's (2026-10-19): the service wide, then
     qty, the unit dropdown, price, the subtotal on the right and a quiet bin.
     The header uses the same tracks, so each heading sits over its box. */
  .line-item-row.priced-line{display:grid;grid-template-columns:minmax(0,1fr) 112px 96px 120px 96px 40px;gap:8px 10px;align-items:center;margin-bottom:10px;}
  .line-item-row.priced-line > input, .line-item-row.priced-line > select{width:100%;min-width:0;}
  .line-item-row.priced-line .line-sub{text-align:right;font-size:14px;font-family:var(--font-ui);color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap;}
  .line-item-row.priced-line.header{font-family:var(--font-ui);font-size:11.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted);margin:2px 0 8px;}
  .line-item-row.priced-line.header .r{text-align:right;}
  .line-bin{width:40px;height:40px;display:grid;place-items:center;padding:0;border:1px solid #E7C9C0;border-radius:var(--radius);background:var(--paper-raised);color:var(--brick);cursor:pointer;}
  .line-bin:hover{background:#FBEDE8;}
  .line-bin .ic{width:16px;height:16px;}
  .lines-label{font-size:12.5px;font-weight:500;color:var(--ink-soft);margin:4px 0 6px;}
  .add-line-btn{display:inline-flex;align-items:center;gap:6px;}
  .add-line-btn .ic{width:14px;height:14px;}
  @media (max-width:760px){
    /* A phone: the service across, then qty, unit, price and the bin. */
    .line-item-row.priced-line{grid-template-columns:repeat(3, minmax(0,1fr)) 40px;}
    .line-item-row.priced-line > :first-child{grid-column:1 / -1;}
    .line-item-row.priced-line .line-sub, .line-item-row.priced-line.header{display:none;}
  }
  /* A phone: every pop-up is a bottom sheet (the design audit, Nick's yes,
     2026-10-19). It rises from the foot of the screen, the full width, round
     on top only, with a grab bar, and its buttons sit above the home bar.
     A sheet taller than the screen starts just below the top and scrolls. */
  @media (max-width:600px){
    .overlay{align-items:flex-end;padding:24px 0 0;}
    .modal, .modal.narrow, .modal.medium, .modal.wide{max-width:none;width:100%;margin:auto 0 0;border-radius:16px 16px 0 0;
      padding-bottom:calc(24px + env(safe-area-inset-bottom));animation:sheetUp .24s cubic-bezier(.2,.8,.2,1);}
    .modal::before{content:"";position:absolute;top:9px;left:50%;width:40px;height:4px;margin-left:-20px;border-radius:2px;background:var(--line-strong);opacity:.8;}
    .modal > .modal-actions{bottom:0;margin-bottom:calc(-24px - env(safe-area-inset-bottom));padding-bottom:calc(16px + env(safe-area-inset-bottom));border-radius:0;}
  }
  @keyframes sheetUp{ from{ transform:translateY(48px); opacity:.5; } to{ transform:none; opacity:1; } }
  @media (prefers-reduced-motion:reduce){ .modal{ animation:none !important; } }
  /* Two or three fields to a row squeeze below readable on a phone. */
  @media (max-width:600px){
    .modal .field-row, .modal .field-row.three{grid-template-columns:1fr;gap:0;}
    /* 16px or an iPhone zooms the page on every tap into a box. */
    .modal input:not([type=checkbox]):not([type=radio]), .modal select, .modal textarea{font-size:16px !important;}
  }

  .form-grid{display:grid;grid-template-columns:1fr;gap:0 14px;}
  @media (min-width:900px){
    .form-grid{grid-template-columns:1fr 1fr;}
  }
  /* A field opts OUT to full width. Per the owner's choice that is text areas:
     each full-width field costs 34-68px of height, and four of them put the
     company form back over the fold. An existing `.field-row` spans too, so no
     form has to be un-paired first. */
  .form-grid > .full,
  .form-grid > .field-row{grid-column:1 / -1;}
  /* Or a long value refuses to shrink and pushes its column past its track:
     the `.auto-col` lesson, and the condition rows before it. */
  .form-grid > *{min-width:0;}
  /* Slightly tighter than a stacked form: with two columns the eye travels
     less vertically, so 14px between rows reads as loose. */
  @media (min-width:900px){
    .form-grid .field{margin-bottom:11px;}
    /* A variation is 12 fields. Stacked three-up that is five sub-rows EACH,
       which is why a three-variation product ran past two screens. At 900px
       the selling fields fit four across and the six measurements fit six
       across, taking a variation from five rows to three. Below 900px both
       stay three-up, exactly as they were. */
    /* Named with BOTH classes: `.field-row.three` is (0,2,0) and a lone class
       is (0,1,0), so the bare selector loses on specificity no matter where it
       sits in the file. The fourth time this trap has bitten here. */
    /* Three columns for a form whose fields are all short: an employee is 20
       of them, and at two columns that is ten rows however wide the modal is. */
    .form-grid.tri{grid-template-columns:repeat(3, minmax(0,1fr));}
  /* A section BLOCK is the grid child where a form is already paired inside its
     own rows: seasonal settings is seven h3-headed sections, so the sections are
     what pair rather than the fields. Start-aligned, because sections have
     genuinely different heights and stretching one leaves its heading floating
     in the middle of a tall box. */
  .form-grid > .ss-block{align-self:start;}
  .form-grid > .ss-block > h3:first-child{margin-top:0;}
    .form-grid.tri > .span-2{grid-column:span 2;}
    /* `.full` spans whatever the grid is, two columns or three. */
    .form-grid.tri > .full{grid-column:1 / -1;}


  }

  /* A quiet group heading. Mechanically reflowing fields in DOM order leaves
     orphans and organises nothing; grouping is what makes a long form
     readable. Sized to cost ~26px so three of them still leave the company
     form inside the fold. */
  .form-section{grid-column:1 / -1;margin:6px 0 8px;font-size:11px;font-weight:600;
    text-transform:uppercase;letter-spacing:0.06em;color:var(--ink-soft);
    padding-bottom:5px;border-bottom:1px solid var(--line);}
  .form-grid > .form-section:first-child{margin-top:0;}

  .field-error-msg{position:absolute;top:0;right:0;color:var(--brick);font-size:11px;font-weight:600;margin:0;white-space:nowrap;}
  .field.field-invalid input,
  .field.field-invalid select{border-color:var(--brick) !important;}
  .modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:20px;}
  .hint{font-size:12px;color:var(--text-muted);margin-top:20px;font-family:var(--font-mono);}
  .pagination{display:flex;justify-content:center;gap:12px;align-items:center;margin-top:14px;padding-bottom:16px;}

  .login-screen{min-height:100vh;display:flex;align-items:center;justify-content:center;background:var(--paper);}
  .login-card{background:var(--paper-raised);border:1px solid var(--line);border-radius:10px;padding:36px 34px;width:100%;max-width:360px;box-shadow:0 4px 20px rgba(31,58,52,0.08);}
  .login-card .brand-mark{font-family:var(--font-display);font-size:22px;font-weight:600;color:var(--ink);display:block;margin-bottom:4px;}
  .login-card .brand-byline{font-size:11px;letter-spacing:0.24em;margin:0 0 10px;}
  .login-card .login-sub{font-size:13px;color:var(--ink-soft);margin:0 0 24px;}
  /* Links on the two pieces of chrome that never had a colour: browser blue on black reads as a broken page. */
  .login-card a,.rail-foot a{color:var(--ink-soft);}
  .login-card .btn{width:100%;margin-top:6px;}
  /* The landscape belongs to the Grainpath look (theme-grainpath.css). */
  .login-art{display:none;}
  .login-error{background:var(--brick-soft);color:#8C332E;font-size:13px;padding:10px 12px;border-radius:var(--radius);margin-bottom:16px;display:none;}
  .login-error.visible{display:block;}


/* ---------- global search ----------
   The panel is absolutely positioned under the box, so .gs-wrap is the
   positioning context. z-index above the page but below modals, which own the
   screen when they are open. */
.gs-wrap{position:relative;margin:0 0 18px;}
.rail-foot .gs-wrap{margin:0;}
/* The dashboard's mount lives in the page header, so it is a fixed-width
   control rather than a field spending a whole row on an empty box. Global
   search already answers from the rail and from the keyboard, so this is the
   third door to one room and has no business being the widest. */
.page-head-actions{display:flex;align-items:center;gap:10px;flex-shrink:0;}
/* A two-word label must never break across two lines: "Add / lead" reads as
   two controls and makes that button taller than the two beside it. */
.page-head-actions .btn{white-space:nowrap;}
/* The search takes whatever is left between the title and the buttons, rather
   than a fixed width. Both neighbours size to their content, so this is the
   only element that can absorb the slack; at a fixed width the header carried
   a gap that moved every time a button appeared or a title got longer.
   min-width stops it collapsing to nothing once three buttons are present. */
.gs-wrap.gs-compact{margin:0;flex:1;min-width:200px;}
/* Matched to the button beside it rather than left to its own content
   height: 33px next to a 36px button reads as a control that did not finish
   loading. The box already centres its children, so the extra 3px is shared. */
.gs-wrap.gs-compact .gs-box{padding:7px 10px;min-height:36px;}
.gs-wrap.gs-compact .gs-box .gs-input{font-size:13px;line-height:18px;}
/* Aligned to the box's RIGHT edge and wider than the box: 260px of results is
   unreadable, and the box now sits near the right of the page, so a panel of
   this width anchored left would hang off the edge. The rail mount solves the
   same problem the other way round, being anchored at the left. */
/* Anchored to the box's RIGHT edge, and sized independently of it. The box is
   elastic now, so a panel matching its width would be unreadable at 200px and
   needlessly wide at 700. Right-anchored because the box sits against the
   buttons, so a left-anchored panel of a fixed width would hang off the page.
   The rail mount solves the same problem the other way round. */
.gs-wrap.gs-compact .gs-panel{left:auto;right:0;width:auto;min-width:340px;max-width:520px;}
.gs-kbd{font-family:var(--font-mono);font-size:10px;color:var(--text-muted);
  border:1px solid var(--line);border-radius:4px;padding:1px 5px;flex-shrink:0;white-space:nowrap;}
/* On a phone the header wraps, so the control takes the line it landed on
   rather than sitting at 260px with dead space beside it. */
/* On a phone the header wraps, so the search takes a line of its own rather
   than being squeezed between a title and three buttons. */
@media (max-width:760px){
  .page-head-actions{width:100%;flex-wrap:wrap;}
  .gs-wrap.gs-compact{flex-basis:100%;min-width:0;}
  .gs-wrap.gs-compact .gs-panel{left:0;right:0;width:auto;min-width:0;max-width:none;}
  /* The strip stacks here, so pushing the clear note right strands it on a
     line of its own with the whole width beside it. It reads as part of the
     list when it simply follows. */
  .alerts-clear{margin-left:0;}
}
.gs-box{display:flex;align-items:center;gap:8px;background:var(--paper-raised);
  border:1px solid var(--line);border-radius:var(--radius);padding:8px 11px;}
.gs-box:focus-within{border-color:var(--line-strong);}
.gs-box .ic{color:var(--text-muted);flex-shrink:0;}
/* .gs-box .gs-input, not .gs-input.
   The generic `input[type="text"], ...` control rule is (0,1,1) and a bare
   class is (0,1,0), so it WON: the input drew its own 1px border, white
   background, 6px radius and 8px padding INSIDE the box's border, which is a
   literal box in a box. It had been that way since global search shipped and
   was merely less obvious at full width. Every property the generic rule sets
   has to be named here, or whichever is missed keeps leaking through. */
.gs-box .gs-input{flex:1;border:0;background:transparent;padding:0;border-radius:0;
  font:inherit;font-size:14px;line-height:20px;color:var(--ink);outline:none;min-width:0;height:auto;}
/* The generic input:focus ring belongs on the box, not on the input inside it. */
.gs-box .gs-input:focus{border:0;box-shadow:none;}
.gs-box:focus-within{box-shadow:0 0 0 2px var(--mustard-soft);}
.gs-clear{border:0;background:transparent;font-size:18px;line-height:1;color:var(--text-muted);cursor:pointer;padding:0 2px;}
.gs-panel{position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:60;}
.gs-results{background:var(--paper-raised);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:0 6px 20px rgba(0,0,0,.10);overflow:hidden;max-height:60vh;overflow-y:auto;}
.gs-hint{margin:0;padding:14px 13px;font-size:13px;color:var(--text-muted);}
.gs-scope-chip{border:1px solid var(--line);background:var(--subtle-bg);border-radius:10px;
  font:inherit;font-family:var(--font-mono);font-size:11px;color:var(--ink-soft);
  padding:1px 7px;margin:2px 1px 0 0;cursor:pointer;}
.gs-scope-chip:hover{border-color:var(--line-strong);}
/* The active scope, stated above the results so the narrowing is never
   invisible: a search that quietly looked in one place would read as a search
   that found little. */
.gs-scopebar{display:flex;align-items:center;gap:8px;padding:7px 13px;
  background:var(--blue-soft);color:var(--ink);font-size:12px;}
.gs-scope-clear{border:0;background:transparent;font:inherit;font-size:12px;
  color:var(--blue);cursor:pointer;text-decoration:underline;padding:0;}
.gs-group + .gs-group{border-top:1px solid var(--line);}
.gs-group-head{display:flex;justify-content:space-between;gap:10px;padding:7px 13px;
  background:var(--subtle-bg);font-size:11px;color:var(--ink-soft);}
/* The navigation path, which is the answer to "how do I find this again".
   Stated once per group rather than repeated on every row. */
.gs-path{color:var(--text-muted);white-space:nowrap;}
.gs-row{display:block;width:100%;text-align:left;border:0;background:transparent;font:inherit;
  color:inherit;cursor:pointer;padding:8px 13px;border-top:1px solid var(--line);}
.gs-row:hover,.gs-row.active{background:var(--subtle-bg);}
.gs-row-title{display:block;font-size:14px;}
.gs-row-sub{display:block;font-size:12px;color:var(--text-muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.gs-more{padding:6px 13px;font-size:11px;color:var(--text-muted);border-top:1px solid var(--line);}
/* In the rail the panel would be clipped by the narrow column, so it opens to
   the right of it at a readable width. */
.rail-foot .gs-panel{left:0;width:340px;right:auto;}

/* ---------- mobile navigation (nothing below changes the desktop rail) ----------
 *
 * Twenty-three tabs in a wrapping strip measured 1123px on an 812px screen, so
 * the menu was taller than the phone and every screen started below it. The
 * bell, the user's name and Log out live in .rail-foot, which is display:none
 * at this width, so a phone could not sign out at all.
 *
 * Both new elements default to display:none, so above 820px they contribute
 * nothing: no layout, no flex participation, no stacking context.
 */
/* Tabs over a list or a record (Orders, a company): underlined, scroll sideways on a phone. */
.list-tabs{display:flex;gap:4px;border-bottom:1px solid var(--line);margin:0 0 14px;overflow-x:auto;scrollbar-width:none;}
.list-tab{font:inherit;font-size:14px;padding:8px 12px;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;background:transparent;color:var(--text-muted);cursor:pointer;white-space:nowrap;}
.list-tab:hover{color:var(--ink);}
.list-tab.on{color:var(--ink);font-weight:600;border-bottom-color:var(--ink);}
html[data-theme="grainpath"] .list-tab.on{border-bottom-color:var(--gp-forest);}
.rail-mobile{display:none;}
/* The phone's tab bar: only a theme that wants it shows it (theme-grainpath.css). */
.tabbar{display:none;}
.nav-pin{display:none;}

@media (max-width:820px){
  /* A COLUMN again. The row-with-wrapping layout is what produced the wall:
     the brand took the left, and twenty-three tabs wrapped down the right. */
  /* Capped so an expanded group can never fill the screen and leave no content
     visible at all - the menu scrolls within itself past that point. A guard,
     not a layout: nothing reaches it until a group is opened. */
  .rail{flex-direction:column;align-items:stretch;gap:10px;padding:12px 16px;
    max-height:80vh;overflow-y:auto;}
  .brand{flex-shrink:0;}

  /* .tabs is a wrapping ROW at this width, which is what lets eight group
     headings sit on three lines instead of eight. This block is not a tab
     though, so it takes a full-width band of its own at the top rather than
     wrapping in among them - without the basis it landed mid-strip and
     stranded whichever heading wrapped next to it. */
  /* A deliberate TWO-COLUMN GRID rather than a wrap. Wrapping mixed two
     visual languages in one ragged flow - icon-and-label tabs and coloured
     uppercase group headings - so Payouts landed beside CRM and Settings was
     orphaned on a line of its own. A grid gives every entry the same cell and
     the block reads as one thing. */
  .tabs{display:grid;grid-template-columns:1fr 1fr;gap:6px;align-content:start;}
  .rail-mobile{display:flex;flex-direction:column;gap:8px;grid-column:1/-1;order:-1;}

  /* Dashboard is the home of the whole tool and was sitting in the wrap as one
     chip among thirteen. Full width, raised, and first. */
  .tabs > .tab[data-view="dashboard"]{grid-column:1/-1;background:var(--paper-raised);
    border-color:var(--line);font-weight:500;font-size:15px;padding:13px 12px;}
  .tabs > .tab[data-view="dashboard"].active{background:var(--sage-soft);
    border-color:var(--sage);color:var(--sage-ink);}

  /* Every other entry is one cell of equal weight, whether it is a loose tab
     or a group heading. The loose tabs need a surface of their own: beside
     the tinted group headings they read as floating text rather than as
     cells, which is most of what made the block look unfinished. */
  .tabs > .tab, .nav-category-head{min-height:44px;border-radius:var(--radius);}
  .tabs > .tab{background:var(--subtle-bg);border-color:var(--line);}
  /* Settings is the gear in the bar at this width, so the grid cell would be a
     second way to the same place. */
  .tabs > .tab[data-view="settings"]{display:none;}
  .tabs > .tab.active{background:var(--paper-raised);border-color:var(--line-strong);}
  .nav-category.expanded{grid-column:1/-1;}
  .nav-category-body.m-open{margin-top:4px;}

  /* The account row the rail foot cannot show at this width. */
  .rail-m-account{display:flex;align-items:center;gap:10px;
    font-size:12px;color:var(--text-muted);font-family:var(--font-mono);}
  #rail-m-user{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}

  /* The toggle that folds the whole menu away. Reads as a control rather than
     a label, because it is the one thing on this bar somebody presses to
     change what they are looking at. */
  .rail-m-menu{display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 10px;
    background:var(--paper-raised);border:1px solid var(--line);border-radius:var(--radius);
    font-family:inherit;font-size:12px;color:var(--ink);cursor:pointer;flex:0 0 auto;}
  .rail-m-menu .ic{width:16px;height:16px;}

  /* Collapsed means GONE. Everything folds away except one bar: the toggle,
     who you are, the bell and Log out. The pinned and recent chips go too -
     they are a fast path, but a fast path that is permanently in the way is
     just more chrome, and the whole point of collapsing is to see the tool.
     The brand goes as well: on a phone toolbar you know which app you are in,
     and it was costing a line of its own. */
  .rail.menu-collapsed{max-height:none;overflow:visible;padding:8px 16px;gap:0;}
  .rail.menu-collapsed .brand,
  .rail.menu-collapsed .rail-m-search,
  .rail.menu-collapsed #rail-m-lists,
  .rail.menu-collapsed .tabs > .tab,
  .rail.menu-collapsed .nav-category{display:none;}
  .rail-m-account-actions{display:flex;align-items:center;gap:6px;flex:0 0 auto;}
  /* Sized as real targets. The bell was 25px and Log out 15px tall, sitting
     6px apart - small enough to mis-tap, and one of them signs you out. */
  .rail-m-icon{position:relative;display:inline-flex;align-items:center;justify-content:center;
    min-width:36px;height:36px;background:none;border:0;padding:0;cursor:pointer;
    color:var(--ink-soft);line-height:0;}
  .rail-m-badge{position:absolute;top:-2px;right:-4px;min-width:14px;height:14px;padding:0 3px;
    border-radius:7px;background:var(--brick);color:#fff;font-size:9px;line-height:14px;text-align:center;}
  .rail-m-logout{display:inline-flex;align-items:center;height:36px;padding:0 6px;
    color:var(--ink-soft);text-decoration:none;}

  .rail-m-search{width:100%;font-family:inherit;font-size:14px;padding:9px 11px;
    border:1px solid var(--line);border-radius:var(--radius);
    background:var(--paper-raised);color:var(--ink);}
  .rail-m-search:focus{outline:none;border-color:var(--line-strong);}

  /* ONE "Quick access" block, built from the SAME cell as the menu grid below
     it. As chips this was a third visual language on a panel that already has
     a full-width Dashboard and a two-column grid, so the panel read as three
     stacked ideas rather than one. Two headings became one for the same
     reason: pinned and recent are a single list of shortcuts, told apart by
     whether the star is lit. */
  .rail-m-quick-group{display:flex;flex-direction:column;gap:5px;}
  .rail-m-group-head{font-family:var(--font-mono);font-size:10px;letter-spacing:0.08em;
    text-transform:uppercase;color:var(--text-muted);}
  .rail-m-quick{display:grid;grid-template-columns:1fr 1fr;gap:6px;}
  .rail-m-quick-cell{display:flex;align-items:center;justify-content:space-between;gap:8px;
    min-height:44px;padding:9px 10px 9px 12px;border:1px solid var(--line);
    border-radius:var(--radius);background:var(--paper-raised);
    font-size:13px;color:var(--ink-soft);cursor:pointer;}
  .rail-m-quick-cell.active{border-color:var(--line-strong);color:var(--ink);font-weight:500;}
  .rail-m-quick-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  /* The star is a target of its own inside the cell, so pinning and navigating
     never compete for the same pixels. */
  .rail-m-quick-pin{display:inline-flex;align-items:center;justify-content:center;
    flex:0 0 auto;min-width:28px;height:28px;margin:-4px -4px -4px 0;
    color:var(--line-strong);line-height:0;}
  .rail-m-quick-pin.pinned{color:var(--mustard);}
  .rail-m-quick-pin .ic{width:14px;height:14px;}

  /* Desktop's open state is neutralised and the mobile one drives the accordion.
     Source order matters here: .m-open must win when both classes are present. */
  .nav-category-body.open{display:none;}
  .nav-category-body.m-open{display:flex;flex-direction:column;flex-wrap:nowrap;}

  /* Filtering hides with a class, never with style.display, which
     applyNavVisibility() owns - the two writing the same property would let a
     cleared search reveal a tab somebody is not allowed to see. */
  .tab.nav-filtered-out{display:none !important;}
  .nav-category.nav-group-filtered-out{display:none !important;}

  /* Every row a comfortable target, and the pin far enough from the label that
     one is not mistaken for the other. */
  .tab{padding:11px 12px;}
  .nav-category-head{padding:10px 12px;}
  .nav-pin{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
    background:none;border:0;padding:4px;margin:-4px -4px -4px 0;cursor:pointer;
    color:var(--line-strong);line-height:0;}
  .nav-pin .ic{width:14px;height:14px;}
  .nav-pin.pinned{color:var(--mustard);}
  /* No pin on a LOOSE top-level tab. Dashboard, Reports, Finance, Payouts and
     Settings are already one tap away with nothing to expand, so a shortcut to
     them saves nothing and five extra stars make the strip read as busy. */
  .tabs > .tab .nav-pin{display:none;}
  /* The count sits between the label and the pin and must not be pushed out. */
  .tab .count{flex:0 0 auto;}
}



/*
 * Money and identifiers in a tabular face. `.font-mono` is used on the
 * marketing hub's spend, revenue and ROAS columns, which are right-aligned
 * figures with decimals - the exact case a proportional face ruins, and the
 * reason a mono face is in the type stack at all.
 *
 * `--font-mono` deliberately never changes with the chosen font set, because
 * it is doing alignment work rather than expressing taste.
 */
.font-mono, .mono{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; }

/* The quiet "optional" marker beside a field label. */
.optional{ font-weight:400; font-size:11px; color:var(--text-muted); text-transform:none; letter-spacing:0; }

/*
 * A neutral callout inside a modal, used by the work-order step panel to
 * explain what Begin and Finish will do. Shaped on `.postage-note` below so
 * the two read as the same kind of aside rather than two inventions.
 */
.alert{
  border:1px solid var(--line); border-left:3px solid var(--line-strong);
  border-radius:var(--radius); padding:10px 12px;
  font-size:12px; color:var(--text-muted);
}
.alert.info{ border-left-color:var(--sage); }


/* ---------- Settings card launcher ---------- */
/*
 * Settings opens on five cards rather than nine stacked sections. Each card
 * lists what is inside it: a tile saying only "Business" makes somebody open
 * all five to find the tax rates, which costs more than the scroll it replaced.
 *
 * auto-fit rather than a fixed column count, so this needs no media query of
 * its own: it lands on three columns wide, two on a tablet and one on a phone,
 * and the mobile rail's own breakpoint is left entirely alone.
 */
.settings-cards{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(240px, 1fr));
  gap:14px;
}
.settings-card{
  display:flex;
  flex-direction:column;
  /* A <button> does not stretch to its grid row the way a div does, so cards
     in the same row came out at different heights depending on how many items
     they list. Measured at three distinct heights before this line. */
  height:100%;
  align-items:flex-start;
  gap:6px;
  text-align:left;
  width:100%;
  font:inherit;
  color:var(--ink);
  cursor:pointer;
  background:var(--panel-bg);
  border:1px solid var(--panel-border);
  border-radius:var(--panel-radius);
  padding:var(--panel-pad);
  /* Reads the block-style tokens like .panel does, so all five block styles
     apply to these without a second set of rules to keep in step. */
  box-shadow:var(--panel-shadow);
}
.settings-card:hover{ border-color:var(--line-strong); }
.settings-card-head{ display:flex; align-items:center; gap:8px; }
.settings-card-title{ font-weight:600; font-size:15px; }
.settings-card-blurb{ display:block; }
/*
 * One item per line, not an inline run.
 *
 * Inline with middot separators was tried first and wrapped badly: a card whose
 * list runs to two lines leaves the separator dangling at the end of the first
 * one ("Theme · Font · Blocks ·"), which reads as a missing item. Stacked has
 * no separator to strand, and it is what makes the list scannable rather than
 * something to read as a sentence.
 */
.settings-card-items{
  display:flex;
  flex-direction:column;
  gap:2px;
  margin-top:4px;
}
.settings-card-items span{
  font-size:12px;
  color:var(--text-muted);
  line-height:1.5;
}

/* ---------- Modal close button ---------- */
/*
 * Every modal gets a close control in its top right, injected centrally rather
 * than written into all 136 overlays by hand.
 *
 * Escape and clicking the backdrop already closed these, and both still do.
 * Neither is discoverable: somebody who does not know them has no visible way
 * out of a dialog, which is the one place a UI must never leave a person
 * guessing.
 *
 * `.modal` needs position:relative for the button to anchor to, which the base
 * rule does not set. Declared here rather than edited into the base rule so
 * the whole feature is one block that can be removed in one piece.
 */
.modal{position:relative;}
.modal-x{
  position:absolute;
  top:10px;
  right:10px;
  /* 32px is the hit area; the glyph inside is 15px. Small enough to read as
     chrome, large enough to hit with a thumb. */
  width:32px;
  height:32px;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:0;
  border:0;
  border-radius:var(--radius);
  background:transparent;
  color:var(--text-muted);
  cursor:pointer;
  /* Above the modal's own content, so a full-width header or a wide table
     cannot render on top of it. */
  z-index:1;
}
.modal-x:hover{ background:var(--subtle-bg); color:var(--ink); }
.modal-x:focus-visible{ outline:2px solid var(--blue); outline-offset:1px; }
.modal-x .ic{ width:15px; height:15px; }
/*
 * Keep a long title off the button. The heading is still the first child (the
 * button is APPENDED, not prepended, precisely so `h2:first-child` rules and
 * `.modal h2` margins are untouched), so this cannot shift any existing
 * layout.
 */
.modal > h2:first-child{
  padding-right:30px;
  /* Only bites an unbreakable word longer than the heading box, which a real
     title never is. Cheap insurance: without it such a word ignores the
     padding above and runs under the button. */
  overflow-wrap:anywhere;
}


/* ---------------------------------------------------------------------------
 * The app dock: a launcher down the right-hand side, DESKTOP ONLY.
 *
 * The app was capped at 1180px and centred, so on a 1920px screen roughly
 * 370px was margin split evenly either side -- which is why the left looked as
 * wasted as the right. The cap lifts on a wide screen and the dock is what the
 * reclaimed column is for.
 *
 * Hidden below 1280px, so it contributes NO layout on a tablet or a phone: the
 * mobile rail already solves navigation there, and a third column at 375px
 * would push the content off screen.
 * ------------------------------------------------------------------------- */
.dock{ display:none; }

@media (min-width:1280px){
  /* Full width at any size (Nick, 2026-10-19): the menu and the dock meet the
     window's edges on a wide monitor in every theme, rather than the old 1560px cap. */
  .app{ max-width:none; grid-template-columns:220px minmax(0,1fr) 168px; }

  .dock{
    display:block;
    border-left:1px solid var(--line);
    background:var(--paper);
  }

  /* STICKY rather than fixed. Fixed would take the dock out of flow and let
     the dashboard slide underneath it; sticky keeps the grid column reserving
     the space, so the content can never end up behind the tiles. */
  .dock-inner{
    position:sticky; top:0;
    max-height:100vh; overflow-y:auto;
    padding:28px 12px;
    display:flex; flex-direction:column; gap:14px;
  }
}

.dock-heading{
  font-size:10px; letter-spacing:0.06em; text-transform:uppercase;
  color:var(--text-muted); margin-bottom:2px;
}

/* Two columns. Three fitted, but the labels then wrapped to two lines on most
   of them, which made the rows uneven and the whole dock taller. */
.dock-grid{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px 6px; }

.dock-recent{ border-top:1px solid var(--line); padding-top:12px; }

/* Changing the pinned apps (2026-10-18). A cell holds a tile plus its extra
   control: the x while editing, the pin on a Recent tile (on hover or focus). */
.dock-cell{ position:relative; display:flex; justify-content:center; }
.dock-cell > .dock-tile{ width:100%; }
.dock-head-tools{ display:flex; align-items:center; gap:2px; }
.dock-edit{ display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px; padding:0;
  border:1px solid transparent; border-radius:var(--radius); background:transparent; color:var(--ink-soft); cursor:pointer; }
.dock-edit:hover{ background:var(--paper-raised); border-color:var(--line-strong); color:var(--ink); }
.dock-edit .ic{ width:15px; height:15px; }
.dock-done{ font:inherit; font-family:var(--font-ui); font-size:11px; padding:3px 9px; border-radius:6px; cursor:pointer;
  border:1px solid var(--line-strong); background:var(--paper-raised); color:var(--ink); }
.dock-x, .dock-pin{ position:absolute; top:-6px; left:calc(50% + 14px); width:20px; height:20px; padding:0; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center; cursor:pointer;
  border:1px solid var(--line-strong); background:var(--paper-raised); color:var(--ink-soft); }
.dock-x:hover, .dock-pin:hover{ color:var(--ink); border-color:var(--ink-soft); }
.dock-x .ic, .dock-pin .ic{ width:11px; height:11px; }
.dock-pin{ opacity:0; pointer-events:none; transition:opacity .12s ease; }
.dock-cell:hover .dock-pin, .dock-cell:focus-within .dock-pin{ opacity:1; pointer-events:auto; }
.dock-editing .dock-tile-edit{ cursor:grab; touch-action:none; user-select:none; }
.dock-dragging{ opacity:.45; }
/* While editing the x takes the corner the count would hang from. */
.dock-editing .dock-pinned .dock-badge{ display:none; }
.dock-dragging .dock-tile-edit{ cursor:grabbing; }
.dock-add{ border:1.5px dashed var(--line-strong); background:transparent; color:var(--ink-soft); }
.dock-hint{ margin:-4px 0 0; font-size:10px; color:var(--text-muted); font-family:var(--font-ui); }
.dock-reset{ font:inherit; padding:0; border:0; background:none; color:var(--ink-soft); text-decoration:underline; cursor:pointer; }
.dock-pick-top{ display:flex; align-items:center; gap:12px; margin-bottom:8px; }
.dock-pick-top input{ flex:1; }
.dock-pick-list{ max-height:min(56vh, 460px); overflow-y:auto; margin:0 -4px; padding:0 4px; }
.dock-pick-head{ font-size:10px; letter-spacing:.08em; text-transform:uppercase; color:var(--text-muted); margin:12px 0 2px; }
.dock-pick-row{ display:flex; align-items:center; gap:10px; width:100%; padding:8px 6px; border:0; border-bottom:1px solid var(--line);
  background:transparent; color:var(--ink); font:inherit; font-size:13px; text-align:left; cursor:pointer; }
.dock-pick-row:hover{ background:var(--paper); }
.dock-pick-row > .ic{ width:16px; height:16px; color:var(--ink-soft); }
.dock-pick-name{ flex:1; }
.dock-pick-state{ display:inline-flex; align-items:center; gap:5px; font-size:12px; color:var(--sage-ink, var(--ink-soft)); }
.dock-pick-state .ic{ width:13px; height:13px; }
.dock-pick-row.pinned .dock-pick-state{ color:var(--ink-soft); }
html[data-scheme="dark"] .dock-pick-state{ color:var(--ink-soft); }

.dock-tile{
  display:flex; flex-direction:column; align-items:center; gap:5px;
  background:none; border:0; padding:2px 0; cursor:pointer;
  font-family:var(--font-ui); color:var(--ink-soft);
}
.dock-tile:hover{ color:var(--ink); }
.dock-tile:hover .dock-icon{ border-color:var(--line-strong); }

/* The rounded square. position:relative so the badge can hang off its corner. */
.dock-icon{
  position:relative;
  width:46px; height:46px; border-radius:13px;
  border:1px solid var(--line);
  background:var(--paper-raised);
  display:flex; align-items:center; justify-content:center;
}
.dock-icon .ic{ width:22px; height:22px; }

/* One tint per pinned tile, so the six are told apart without reading six
   labels. Text from the SAME hue as the fill, the standing rule: --ink on a
   colour reads as a mistake. Recents stay neutral on purpose -- they are
   transient, and colouring them would make the dock read as twelve equally
   important things. */
.dock-tint-violet{ background:var(--violet-soft); border-color:transparent; color:var(--violet-ink); }
.dock-tint-sage{   background:var(--sage-soft);   border-color:transparent; color:var(--sage-ink); }
.dock-tint-mustard{background:var(--mustard-soft);border-color:transparent; color:var(--mustard-ink); }
.dock-tint-blue{   background:var(--blue-soft);   border-color:transparent; color:var(--blue-ink); }
.dock-tint-brick{  background:var(--brick-soft);  border-color:transparent; color:var(--brick-ink); }
.dock-tint-plum{   background:var(--plum-soft);   border-color:transparent; color:var(--plum-ink); }

/* The count. Solid rather than tinted: this one is meant to be seen from the
   other side of the screen, which is the whole job of a notification badge. */
.dock-badge{
  position:absolute; top:-5px; right:-5px;
  min-width:19px; height:19px; padding:0 5px;
  border-radius:999px;
  background:var(--brick); color:#fff;
  font-size:11px; font-weight:500; line-height:19px;
  text-align:center;
  border:2px solid var(--paper);
}
.dock-badge[hidden]{ display:none; }

.dock-label{
  font-size:10px; line-height:1.25; text-align:center;
  max-width:66px;
  /* Two lines then clip. A third line makes one tile taller than the five
     beside it, which is the uneven-row problem the grid exists to avoid. */
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden;
}



/* ---------- core additions for the modular shell ---------- */

/* Below 760px every list collapses to one column. In GnomeWork each feature
   row was named here one by one; the shell states the rule once and a module
   whose row must NOT collapse opts out in its own stylesheet. */
@media (max-width:760px){
  .row:not(.head){grid-template-columns:1fr !important;gap:4px;}
  .row.head{display:none;}
}

/* The brand accent, emitted by the Blade shell from the tenant's brand JSON,
   reaches the chrome through one token. A tenant with no accent set inherits
   the theme's own. */
:root{--brand-accent:var(--mustard);}
.brand-mark{color:var(--ink);}
.brand-logo{height:26px;width:auto;max-width:150px;display:inline-block;vertical-align:middle;}
/* The light mark is for a dark menu only; the Grainpath theme swaps the two. */
.brand-logo-on-dark{display:none;}

/* The count beside a tab. Rendered by the shell from the manifest as
   <span class="count" data-count="id">, filled by updateCounts(). */
.tab .count[data-count]:empty{display:none;}

/* An empty rail while modules load, or a tenant with nothing enabled. */
.rail-empty{font-size:12px;color:var(--text-muted);padding:10px 12px;}

/* The shell reports a manifest view with no registered renderer here. */
.view-missing{padding:40px 20px;text-align:center;color:var(--ink-soft);}

/* A "?" beside a label, with the explanation behind it rather than in a
   paragraph under every field (helpTipHtml in platform.js). */
.help-tip{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;
  border-radius:50%;border:1px solid var(--line-strong);background:transparent;color:var(--ink-soft);
  font-family:var(--font-ui);font-size:11px;font-weight:600;line-height:1;cursor:pointer;padding:0;
  margin-left:6px;vertical-align:middle;flex:0 0 auto;}
.help-tip:hover,.help-tip[aria-expanded="true"]{background:var(--ink-soft);color:var(--paper);border-color:var(--ink-soft);}
.help-bubble{display:none;position:absolute;z-index:220;max-width:320px;background:var(--paper-raised);
  border:1px solid var(--line-strong);border-radius:var(--radius);box-shadow:0 6px 20px rgba(0,0,0,0.14);
  padding:10px 12px;font-size:12px;line-height:1.55;color:var(--ink);}

/* ---------------------------------------------------------------------------
 * Tucking the menu and the app dock away (desktop only)
 *
 * The state is a class on <html> (rail-collapsed, dock-hidden), set by
 * installShellPanels() from this device's saved choice. The page grid's
 * columns animate between the two widths; `shell-no-anim` switches that off
 * for the state a page opens in, so only a click slides. Below 821px none of
 * this applies: the compact top menu is in charge there.
 * ------------------------------------------------------------------------- */
.rail-toggle, .dock-toggle, .dock-reveal{ display:none; }

@media (min-width:821px){
  .app{ transition:grid-template-columns .25s ease; }
  html.shell-no-anim .app, html.shell-no-anim .app *, html.shell-no-anim .dock-reveal{ transition:none !important; animation:none !important; }

  .rail-toggle{ display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; align-self:center;
    width:30px; height:30px; padding:0; margin-left:6px; border-radius:var(--radius);
    border:1px solid transparent; background:transparent; color:var(--ink-soft); cursor:pointer; }
  .rail-toggle:hover{ background:var(--paper-raised); border-color:var(--line-strong); color:var(--ink); }
  .rail-toggle .ic{ width:18px; height:18px; }

  html.rail-collapsed .app{ grid-template-columns:64px 1fr; }
  html.rail-collapsed .rail{ padding:24px 8px; overflow:hidden; }
  html.rail-collapsed .brand{ flex-direction:column; align-items:center; gap:4px; }
  /* Folded, the mark stays at the top and the name goes. */
  html.rail-collapsed .brand-lockup{ display:none; }
  html.rail-collapsed .rail .brand-logo{ height:24px; margin:0 0 4px; }
  html.rail-collapsed .brand-bell, html.rail-collapsed .rail-toggle{ margin-left:0; }
  html.rail-collapsed .rail .tab{ justify-content:center; padding:9px 0; position:relative; }
  html.rail-collapsed .rail .tab-label{ font-size:0; gap:0; }
  html.rail-collapsed .rail .tab .count{ position:absolute; top:1px; right:1px; font-size:9px; line-height:1; padding:2px 3px;
    border-radius:8px; background:var(--paper-raised); border:1px solid var(--line); }
  html.rail-collapsed .rail .tab .count:empty, html.rail-collapsed .rail .tab .count[data-zero]{ display:none; }
  /* A group heading becomes a short tinted bar that still opens and closes its group. */
  html.rail-collapsed .nav-category-head{ height:9px; padding:0; margin:6px 8px 4px; font-size:0; border-radius:5px;
    background:var(--cat-accent, var(--line-strong)); opacity:.55; }
  html.rail-collapsed .nav-category-head:hover{ opacity:1; box-shadow:none; }
  html.rail-collapsed .nav-caret{ display:none; }
  /* Folded, the foot is just the initials; the menu still opens from them. */
  html.rail-collapsed .acct-name, html.rail-collapsed .acct-btn .acct-sel{ display:none !important; }
  html.rail-collapsed .acct-btn{ justify-content:center; padding:6px 0; }
}

@media (min-width:1280px){
  html.rail-collapsed .app{ grid-template-columns:64px minmax(0,1fr) 168px; }
  html.dock-hidden .app{ grid-template-columns:220px minmax(0,1fr) 0px; }
  html.rail-collapsed.dock-hidden .app{ grid-template-columns:64px minmax(0,1fr) 0px; }

  /* The dock keeps its full width inside while its column shrinks, so its
     tiles slide out rather than squashing, and fade as they go. */
  /* clip, not hidden: hidden makes the dock its own scroll box, and then the sticky
     inner never stays put on a long page. clip hides the slide-away just the same. */
  .dock{ overflow:clip; min-width:0; transition:border-color .25s ease; }
  .dock-inner{ width:168px; transition:opacity .2s ease; }
  html.dock-hidden .dock{ border-left-color:transparent; }
  html.dock-hidden .dock-inner{ opacity:0; pointer-events:none; }

  .dock-head-row{ display:flex; align-items:center; justify-content:space-between; gap:6px; }
  .dock-head-row .dock-heading{ margin-bottom:0; }
  .dock-toggle{ display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px; padding:0;
    border-radius:var(--radius); border:1px solid transparent; background:transparent; color:var(--ink-soft); cursor:pointer; }
  .dock-toggle:hover{ background:var(--paper-raised); border-color:var(--line-strong); color:var(--ink); }
  .dock-toggle .ic{ width:17px; height:17px; }

  /* The tab on the right edge that brings the dock back. */
  html.dock-hidden .dock-reveal{ display:flex; align-items:center; justify-content:center; position:fixed; right:0; top:96px; z-index:40;
    width:26px; height:58px; padding:0; border:1px solid var(--line-strong); border-right:none; border-radius:10px 0 0 10px;
    background:var(--paper-raised); color:var(--ink-soft); cursor:pointer; box-shadow:-2px 2px 8px rgba(0,0,0,.08);
    animation:dockRevealIn .25s ease; }
  html.dock-hidden .dock-reveal:hover{ color:var(--ink); width:30px; }
  .dock-reveal .ic{ width:15px; height:15px; }
  /* Dragged up and down the edge (installDockRevealDrag): a finger moves it rather than the page. */
  html.dock-hidden .dock-reveal{ touch-action:none; }
  html.dock-hidden .dock-reveal.dragging{ cursor:grabbing; width:30px; color:var(--ink); }
}
@keyframes dockRevealIn{ from{ transform:translateX(100%); } to{ transform:translateX(0); } }

/* ---------------------------------------------------------------------------
 * Personal custom fields and the Columns menu
 * ------------------------------------------------------------------------- */
.cf-tag{ display:inline-block; font-size:10.5px; border-radius:6px; padding:1px 7px; margin-left:6px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; vertical-align:middle; }
.cf-tag.biz{ background:var(--sage-soft); color:var(--sage-ink); }
.cf-tag.mine{ background:var(--mustard-soft); color:var(--mustard-ink); }
.cf-detail-sub{ font-size:11.5px; color:var(--ink-soft); margin:8px 0 4px; }
.cf-input[disabled]{ opacity:.75; cursor:not-allowed; }
.bf-tabs{ margin:6px 0 10px; }
.cf-host{ margin-top:14px; }
.cf-host:empty{ display:none; }
.cf-grid{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px 14px; }
.cf-grid .field.full{ grid-column:1 / -1; }
@media (max-width:640px){ .cf-grid{ grid-template-columns:1fr; } }
.cf-req{ color:var(--brick); }
.cf-empty{ color:var(--text-muted); }
.cf-detail{ margin-top:12px; max-width:720px; border:1px solid var(--line); border-radius:10px; padding:10px 14px; background:var(--paper-raised); }
.cf-detail-head{ display:flex; justify-content:space-between; align-items:center; font-size:12px; font-weight:600; color:var(--ink-soft); margin-bottom:6px; }
.cf-detail-list{ display:grid; grid-template-columns:minmax(120px,auto) 1fr; gap:4px 16px; margin:0; font-size:13px; }
.cf-detail-list dt{ color:var(--ink-soft); }
.cf-detail-list dd{ margin:0; min-width:0; overflow-wrap:anywhere; }
.cf-type-chips{ display:flex; flex-wrap:wrap; gap:6px; }
.cf-chip{ font:inherit; font-size:12px; padding:5px 11px; border-radius:20px; border:1px solid var(--line-strong); background:transparent; color:var(--ink); cursor:pointer; }
.cf-chip:hover:not(:disabled){ background:var(--paper-raised); }
.cf-chip.on{ background:var(--ink); border-color:var(--ink); color:var(--paper); }
.cf-chip:disabled:not(.on){ opacity:.45; cursor:default; }
.cf-manage{ display:flex; flex-direction:column; }
.cf-manage-row{ display:grid; grid-template-columns:minmax(0,1fr) auto auto; gap:10px; align-items:center; padding:8px 0; border-bottom:1px solid var(--line); }
.cf-manage-name{ font-weight:600; font-size:14px; }
.cf-manage-actions{ display:flex; gap:4px; }
.btn.cf-danger{ color:var(--brick); }
.cf-filter-choices{ display:flex; flex-direction:column; gap:4px; }

.list-columns-panel{ min-width:240px; max-width:280px; }
.list-col-rows{ display:flex; flex-direction:column; gap:1px; }
.list-col-row{ display:flex; align-items:center; gap:6px; padding:4px 4px; border-radius:6px; font-size:13px; }
.list-col-row:hover{ background:var(--paper); }
.list-col-row label{ display:flex; align-items:center; gap:8px; margin:0; font-weight:400; cursor:pointer; flex:1; min-width:0; }
.list-col-row.is-dragging{ background:var(--paper); box-shadow:0 2px 8px rgba(0,0,0,.12); }
.list-col-grip{ display:inline-flex; color:var(--text-muted); cursor:grab; touch-action:none; }
.list-col-grip[hidden]{ display:inline-flex; visibility:hidden; }
.list-col-grip .ic{ width:14px; height:14px; }
.list-col-sub{ font-size:11px; letter-spacing:.05em; text-transform:uppercase; color:var(--text-muted); margin:10px 4px 4px; padding-top:8px; border-top:1px solid var(--line); }
.list-col-none{ margin:2px 4px; font-size:12px; }
.list-col-actions{ display:flex; flex-direction:column; align-items:flex-start; gap:4px; margin-top:8px; padding-top:8px; border-top:1px solid var(--line); }
.list-col-link{ font:inherit; font-size:13px; background:none; border:none; padding:3px 4px; color:var(--blue); cursor:pointer; }
.list-col-link:hover{ text-decoration:underline; }
.list-col-link.muted{ color:var(--ink-soft); }

.list-col-hint{ margin:0 4px 6px; font-size:11px; color:var(--text-muted); }

/* Links inside list cells (email, website, a link field): the app blue, underlined on hover only. */
.row .sub-text a{ color:var(--blue); text-decoration:none; }
.row .sub-text a:hover{ text-decoration:underline; }

/* Dragging a column by its header (design audit, 2026-09-29): the header
   lifts, its column fades and leaves a dashed slot, and a slim accent line
   sits in the gap where it lands. Mouse and pen only; see startListHeaderDrag(). */
.row.head [data-col-key]:not([data-col-fixed]){ position:relative; user-select:none; }
.row.head [data-col-key]:not([data-col-fixed]):not(.sortable){ cursor:grab; }
/* A grip appears on hover, so a header says it can be moved. */
.row.head [data-col-key]:not([data-col-fixed])::before{ content:''; position:absolute; left:-14px; top:50%; width:10px; height:10px; margin-top:-5px;
  opacity:0; transition:opacity .12s ease; background:var(--ink-soft);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Ccircle cx='3' cy='2' r='1'/%3E%3Ccircle cx='7' cy='2' r='1'/%3E%3Ccircle cx='3' cy='5' r='1'/%3E%3Ccircle cx='7' cy='5' r='1'/%3E%3Ccircle cx='3' cy='8' r='1'/%3E%3Ccircle cx='7' cy='8' r='1'/%3E%3C/svg%3E") center / contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Ccircle cx='3' cy='2' r='1'/%3E%3Ccircle cx='7' cy='2' r='1'/%3E%3Ccircle cx='3' cy='5' r='1'/%3E%3Ccircle cx='7' cy='5' r='1'/%3E%3Ccircle cx='3' cy='8' r='1'/%3E%3Ccircle cx='7' cy='8' r='1'/%3E%3C/svg%3E") center / contain no-repeat; }
.row.head [data-col-key]:not([data-col-fixed]):hover::before{ opacity:1; }
body.col-dragging .row.head [data-col-key]::before{ opacity:0 !important; }
/* The column being moved: a dashed slot where its header was, its cells faded. */
.row.head [data-col-key].is-col-dragging{ color:transparent; }
.row.head [data-col-key].is-col-dragging::after{ content:''; position:absolute; inset:-8px -6px; border:1px dashed var(--line-strong); border-radius:6px; }
.is-col-dragging-cell{ opacity:.4; transition:opacity .12s ease; }
/* The lifted header. */
.col-drag-ghost{ position:fixed; z-index:1000; pointer-events:none; display:flex; align-items:center; gap:7px; padding:0 12px;
  box-sizing:border-box; background:var(--paper); border:1px solid var(--line-strong); border-radius:6px;
  box-shadow:0 6px 16px rgba(0,0,0,.14); transform:rotate(-1.5deg);
  font-family:var(--font-mono); font-size:10px; letter-spacing:.08em; text-transform:uppercase; color:var(--ink); white-space:nowrap; overflow:hidden; }
.col-drag-ghost .ic{ width:13px; height:13px; flex:none; color:var(--ink-soft); }
.col-drag-ghost span{ overflow:hidden; text-overflow:ellipsis; }
/* The landing line: slim, the accent colour, header height with a short fade and a round cap. */
.col-drop-line{ position:fixed; width:2px; background:var(--blue); z-index:1001; pointer-events:none; border-radius:1px; }
.col-drop-line::before{ content:''; position:absolute; top:-3px; left:-2px; width:6px; height:6px; border-radius:50%; background:var(--blue); }
.col-drop-line::after{ content:''; position:absolute; top:100%; left:0; width:2px; height:24px; background:linear-gradient(var(--blue), transparent); }
body.col-dragging, body.col-dragging *{ cursor:grabbing !important; user-select:none; }

/* ---------------------------------------------------------------------------
 * The touch form (design audit, 2026-09-29): Type, Date and Time on one row
 * that stacks properly on a phone, the contact's local time as a quiet line,
 * and Delete on the far left, away from Cancel.
 * ------------------------------------------------------------------------- */
.field-row.touch-when{ grid-template-columns:minmax(0,1.2fr) minmax(0,1fr) minmax(0,0.8fr); }
@media (max-width:560px){
  .field-row.touch-when{ grid-template-columns:minmax(0,1fr) minmax(0,1fr); }
  .field-row.touch-when > .field:first-child{ grid-column:1 / -1; }
}
.touch-form-sub{ margin:-6px 0 14px; }
.touch-local-time{ margin:5px 0 0; font-size:12px; color:var(--ink-soft); font-family:var(--font-ui); }
.touch-local-time:empty{ display:none; }
.touch-remove-phone{ color:var(--brick); margin:-4px 0 10px; }
.touch-remove-phone[hidden]{ display:none; }
.modal-actions .touch-delete{ margin-right:auto; }

/* Settings > Appearance: date format. */
.date-format-list{ display:flex; flex-direction:column; gap:4px; max-width:420px; }
.date-format-opt{ display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:8px; border:1px solid transparent; cursor:pointer; font-size:14px; }
.date-format-opt:hover{ background:var(--paper); }
.date-format-opt.on{ background:var(--paper); border-color:var(--line); }
.date-format-ex{ margin-left:auto; font-family:var(--font-mono); font-size:12px; color:var(--ink-soft); }

/* ---------------------------------------------------------------------------
 * Field search (2026-09-29): "payment terms: net 30" becomes a chip inside the
 * search box, with field suggestions below it and a line under the toolbar
 * saying what is being searched, or that the list has no such field.
 * ------------------------------------------------------------------------- */
.field-search{ flex:1; min-width:180px; position:relative; display:flex; align-items:center; gap:4px; padding-left:6px;
  border:1px solid var(--line-strong); border-radius:var(--radius); background:var(--paper-raised); }
.field-search:focus-within{ border-color:var(--mustard); box-shadow:0 0 0 2px var(--mustard-soft); }
.field-search input.search{ flex:1; min-width:70px; width:0; border:none; box-shadow:none; background-color:transparent; padding-left:4px; }
.field-search input.search:focus{ border:none; box-shadow:none; }
.field-search-chip{ display:inline-flex; align-items:center; gap:2px; flex:0 1 auto; min-width:0; max-width:60%; white-space:nowrap; padding:2px 2px 2px 8px;
  border-radius:6px; background:var(--mustard-soft); color:var(--ink); font-size:12px; font-weight:600; }
.field-search-chip-label{ min-width:0; overflow:hidden; text-overflow:ellipsis; }
/* On a phone the box takes its own row, with the buttons beneath it, and a
   Filters or Columns panel opens the full width of the toolbar rather than
   hanging off whichever side its button landed on. */
@media (max-width:560px){
  .field-search{ flex-basis:100%; }
  .toolbar{ position:relative; }
  .toolbar > .filter-menu{ position:static; }
  .toolbar > .filter-menu > .filter-menu-panel{ left:0; right:0; min-width:0; max-width:none; }
}
.field-search-chip[hidden]{ display:none; }
.field-search-chip-x{ border:none; background:transparent; color:inherit; cursor:pointer; font-size:15px; line-height:1;
  width:22px; height:22px; border-radius:4px; padding:0; }
.field-search-chip-x:hover{ background:rgba(0,0,0,0.08); }
.field-search-menu{ position:absolute; top:100%; left:0; margin-top:4px; min-width:260px; max-width:100%; z-index:60; padding:4px;
  background:var(--paper-raised); border:1px solid var(--line); border-radius:8px; box-shadow:0 4px 10px rgba(0,0,0,0.1); }
.field-search-menu[hidden]{ display:none; }
.field-search-item{ display:flex; align-items:center; gap:12px; padding:7px 9px; border-radius:6px; font-size:13px; cursor:pointer; }
.field-search-item.on, .field-search-item:hover{ background:var(--paper); }
.field-search-item-tail{ margin-left:auto; font-family:var(--font-mono); font-size:12px; color:var(--ink-soft); }
.field-search-hint{ margin:-10px 0 14px; font-size:12px; color:var(--ink-soft); }
.field-search-hint.warn{ color:var(--brick); }
.field-search-hint[hidden]{ display:none; }

/* ---------------------------------------------------------------------------
 * The dashboard revamp (2026-09-30, from the design audit of the same day).
 *
 * ONE frame per panel: the panel reads the block-style tokens like .panel
 * does (so Framed, Flat, Elevated, Ruled and Compact all apply) and a panel
 * built from .dp draws its own header row, flush rows and dividers with no
 * boxes inside it. Each count is said once, in the stat strip or in a panel
 * header's pill. Lists stop at five rows and say how many more.
 * ------------------------------------------------------------------------- */
.dashboard-section{ background:var(--panel-bg); border:var(--panel-border); border-radius:var(--panel-radius); box-shadow:var(--panel-shadow); }
.dashboard-section:has(> .dp), .dashboard-section:has(> .dash-panel-body > .dp){ padding:0; overflow:hidden; }
.dashboard-grid.is-editing > .dashboard-section:has(> .dash-panel-body > .dp) > .dash-controls{ margin:10px 12px 0; }

.dashboard-head{ align-items:center; margin-bottom:16px; }
.dashboard-date{ font-size:13px; color:var(--ink-soft); margin-top:2px; }
.btn.icon-only{ padding:8px 10px; line-height:0; }
.btn.icon-only .ic{ width:16px; height:16px; margin:0; }

.dp{ display:flex; flex-direction:column; min-height:100%; }
/* A header never shrinks: in a panel sized by hand the frame has a fixed height, and a
   header that wraps its controls onto a second line must grow, not let them spill over
   what is beneath it. */
.dp > .dp-head{ flex-shrink:0; }
.dp-head{ display:flex; align-items:center; gap:8px; min-height:46px; padding:8px 16px; border-bottom:1px solid var(--line); flex-wrap:wrap; }
.dp-title{ font-family:var(--font-display); font-size:16px; font-weight:600; margin:0; line-height:1.3; }
.dp-sub{ font-size:12px; color:var(--ink-soft); }
.dp-pill{ font-size:12px; font-weight:500; padding:2px 9px; border-radius:20px; background:var(--subtle-bg); color:var(--ink-soft); white-space:nowrap; }
.dp-pill.late{ background:var(--brick-soft); color:#8C332E; }
.dp-link{ margin-left:auto; font:inherit; font-size:12px; color:var(--ink-soft); background:none; border:none; cursor:pointer; padding:6px 0; white-space:nowrap; }
.dp-link:hover{ color:var(--ink); text-decoration:underline; }
.dp-seg{ display:inline-flex; margin-left:auto; border:1px solid var(--line-strong); border-radius:6px; overflow:hidden; }
.dp-seg-btn{ font:inherit; font-size:12px; padding:3px 9px; border:none; border-right:1px solid var(--line); background:transparent; color:var(--ink-soft); cursor:pointer; }
.dp-seg-btn:last-child{ border-right:none; }
.dp-seg-btn.on{ background:var(--subtle-bg); color:var(--ink); font-weight:600; }
.dp-seg + .dp-link{ margin-left:12px; }

.dp-rows{ display:flex; flex-direction:column; }
.dp-row{ display:flex; align-items:center; gap:10px; min-height:44px; padding:7px 16px; border-bottom:1px solid var(--line); font-size:13px; cursor:pointer; }
.dp-row:last-child{ border-bottom:none; }
.dp-row:hover{ background:var(--subtle-bg); }
.dp-row.is-static{ cursor:default; }
.dp-row.is-static:hover{ background:transparent; }
.dp-row-main{ flex:1; min-width:0; }
.dp-row-title{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; color:var(--ink); }
.dp-row-meta{ font-size:12px; color:var(--ink-soft); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dp-row-end{ font-size:12px; color:var(--ink-soft); white-space:nowrap; font-variant-numeric:tabular-nums; }
.dp-row-end.late{ color:var(--brick); font-weight:500; }
.dp-dot{ width:8px; height:8px; border-radius:50%; background:var(--line-strong); flex:none; }
/* A tick box at the start of a row (the To do panel): ticks the item done in place. */
.dp-check{ appearance:none; -webkit-appearance:none; flex:none; width:18px; height:18px; margin:0; border:1.5px solid var(--line-strong);
  border-radius:5px; background:var(--paper-raised); cursor:pointer; display:inline-grid; place-content:center; transition:background .12s ease, border-color .12s ease; }
.dp-check:hover{ border-color:var(--ink-soft); }
.dp-check:checked{ background:var(--ink); border-color:var(--ink); }
.dp-check:checked::after{ content:''; width:9px; height:5px; border:2px solid var(--paper-raised); border-top:0; border-right:0; transform:translateY(-1px) rotate(-45deg); }
html[data-theme="grainpath"] .dp-check:checked{ background:var(--gp-forest); border-color:var(--gp-forest); }
.dp-row.ticked .dp-row-title{ text-decoration:line-through; color:var(--text-muted); }

/* The node loader (Nick, 2026-10-19): the Grainpath node redrawn in
   assets/brand/loader.svg, each node growing and shrinking on its own rhythm.
   It is a MASK over the theme's ink, so it takes each theme's colour (the
   drawing's own sage in Grainpath). .app-loading fills a page or a panel
   (appLoadingHtml), fading in after a moment so a quick screen never flashes
   it; .is-loading puts the small one beside a placeholder's "Loading…", and
   .is-loading.lg is the big one for a list or a page body. */
:root{ --loader-ink:var(--ink-soft); }
html[data-theme="grainpath"]{ --loader-ink:#6B7567; }
.app-loading-mark, .is-loading::before{ flex:none; background-color:var(--loader-ink);
  -webkit-mask:url("../brand/loader.svg") center / contain no-repeat; mask:url("../brand/loader.svg") center / contain no-repeat; }
.app-loading{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px;
  min-height:min(60vh, 520px); padding:40px 16px; color:var(--text-muted); text-align:center; animation:appLoadingIn .25s ease .15s both; }
.app-loading-mark{ width:64px; height:64px; }
.app-loading p{ margin:0; font-size:14px; }
.app-loading p:empty{ display:none; }
@keyframes appLoadingIn{ from{ opacity:0; } to{ opacity:1; } }
/* Arriving at a screen still fetching: the loader in front of the screen being left (render()). */
#view-root > .app-loading.view-wait ~ *{ display:none; }
.dashboard-grid > .app-loading{ grid-column:1 / -1; min-height:320px; }
.is-loading{ display:flex; align-items:center; gap:10px; }
span.is-loading{ display:inline-flex; }
.is-loading::before{ content:""; width:22px; height:22px; }
.is-loading.lg{ flex-direction:column; justify-content:center; gap:12px; min-height:200px; text-align:center; }
.is-loading.lg::before{ width:52px; height:52px; }
.dp-dot.late{ background:var(--brick); }
.dp-icon{ display:inline-flex; color:var(--ink-soft); flex:none; }
.dp-icon-btn{ display:inline-flex; align-items:center; justify-content:center; width:32px; height:32px; flex:none; border:1px solid var(--line-strong); border-radius:var(--radius); background:transparent; color:var(--ink); cursor:pointer; }
.dp-icon-btn:hover{ background:var(--paper); }
.dp-icon-btn .ic{ width:16px; height:16px; margin:0; }
.dp-row .btn.small{ min-height:32px; }
.dp-more{ display:block; width:100%; text-align:left; font:inherit; font-size:12px; color:var(--ink-soft); background:none; border:none; border-top:1px solid var(--line); padding:9px 16px; cursor:pointer; }
.dp-more:hover{ color:var(--ink); background:var(--subtle-bg); }
.dp-empty{ margin:0; padding:16px; font-size:13px; color:var(--ink-soft); }
.dp-subhead{ display:flex; align-items:center; gap:8px; padding:12px 16px 6px; border-top:1px solid var(--line); font-size:12px; font-weight:600; color:var(--ink-soft); }
.dp-pad{ padding:14px 16px; }
.dp-chart{ position:relative; height:210px; padding:12px 14px 8px; }

/* Horizontal bars (pipeline, reps): a label, a track, the figure. */
.dp-bars{ display:flex; flex-direction:column; gap:2px; padding:10px 8px; }
.dp-bar-row{ display:grid; grid-template-columns:minmax(0,96px) minmax(0,1fr) auto; align-items:center; gap:10px; width:100%; min-height:36px; padding:4px 8px; border:none; border-radius:6px; background:none; font:inherit; font-size:13px; color:var(--ink); text-align:left; cursor:pointer; }
.dp-bar-row:hover{ background:var(--subtle-bg); }
.dp-bar-row.is-static{ cursor:default; }
.dp-bar-row.is-static:hover{ background:none; }
.dp-bar-label{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dp-bar-track{ height:10px; border-radius:5px; background:var(--subtle-bg); overflow:hidden; }
.dp-bar-fill{ display:block; height:100%; border-radius:5px; background:var(--green-dot); }
.dp-bar-fill.stage-lead{ background:var(--blue); }
.dp-bar-fill.stage-prospect{ background:var(--yellow-dot); }
.dp-bar-fill.stage-customer{ background:var(--green-dot); }
.dp-bar-value{ font-size:12px; color:var(--ink-soft); font-variant-numeric:tabular-nums; min-width:36px; text-align:right; }

/* One bar split into parts (receivables by age), with its legend under it. */
.dp-stack{ display:flex; height:14px; border-radius:7px; overflow:hidden; background:var(--subtle-bg); gap:2px; }
.dp-stack-seg{ display:block; height:100%; min-width:3px; }
.dp-legend{ display:flex; flex-direction:column; margin-top:10px; }
.dp-legend-row{ display:flex; align-items:center; gap:8px; font-size:12px; padding:4px 0; border-bottom:1px solid var(--line); }
.dp-legend-row:last-child{ border-bottom:none; }
.dp-legend-label{ color:var(--ink-soft); }
.dp-legend-value{ margin-left:auto; font-variant-numeric:tabular-nums; color:var(--ink); }
.dp-legend-key{ display:inline-block; width:9px; height:9px; border-radius:2px; flex:none; margin-right:5px; }
.dp-legend-inline{ flex-direction:row; gap:14px; margin:0; padding:0 16px 12px; font-size:12px; color:var(--ink-soft); }

/* The stat strip: every chosen number in one row, divided, not boxed. */
.dash-strip{ display:grid; grid-template-columns:repeat(var(--n), minmax(0,1fr)); margin-bottom:18px; background:var(--panel-bg); border:var(--panel-border); border-radius:var(--panel-radius); box-shadow:var(--panel-shadow); overflow:hidden; }
.dash-stat{ position:relative; display:flex; flex-direction:column; gap:2px; min-width:0; padding:12px 16px; border-right:1px solid var(--line); }
.dash-stat:last-child{ border-right:none; }
.dash-stat.is-link{ cursor:pointer; }
.dash-stat.is-link:hover, .dash-stat.is-link:focus-visible{ background:var(--subtle-bg); outline:none; }
.dash-stat-label{ font-size:12px; color:var(--ink-soft); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dash-stat-value{ font-family:var(--font-display); font-size:26px; font-weight:600; line-height:1.15; font-variant-numeric:tabular-nums; color:var(--ink); }
.dash-stat-value.late{ color:var(--brick); }
.dash-stat-sub{ font-size:12px; color:var(--ink-soft); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dash-stat-sub .up{ color:var(--sage-ink); font-weight:600; }
.dash-stat-sub .down{ color:var(--brick); font-weight:600; }
.dash-stat-remove{ position:absolute; top:6px; right:6px; width:28px; height:28px; border:1px solid var(--line-strong); border-radius:50%; background:var(--paper-raised); color:var(--ink); font-size:16px; line-height:1; cursor:pointer; }
.dash-stat-add{ justify-content:center; background:repeating-linear-gradient(135deg, transparent 0 6px, var(--subtle-bg) 6px 12px); }
.dash-stat-add select{ margin-top:4px; max-width:100%; }

/* Customize: the hot buttons, in the order they will sit. */
.dash-editbar{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:-4px 0 14px; padding:10px 14px; border:1.5px dashed var(--line-strong); border-radius:var(--panel-radius); }
.dash-editbar-label{ font-size:12px; font-weight:600; color:var(--ink-soft); margin-right:4px; }
.dash-editbar-note{ font-size:12px; color:var(--ink-soft); }
.dash-hot-chip{ display:inline-flex; align-items:center; gap:4px; padding:3px 4px 3px 12px; border-radius:20px; background:var(--subtle-bg); font-size:13px; }
.dash-hot-chip button{ width:26px; height:26px; border:none; border-radius:50%; background:transparent; color:var(--ink); font-size:16px; line-height:1; cursor:pointer; }
.dash-hot-chip button:hover{ background:var(--line); }
.dash-tray-group{ display:flex; align-items:center; flex-wrap:wrap; gap:0 6px; margin-bottom:6px; }
.dash-tray-group-name{ font-size:11px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--ink-soft); min-width:64px; margin:0 6px 6px 0; }

.sr-only{ position:absolute !important; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }

@media (max-width:759px){
  .dashboard-head .page-title{ font-size:24px; }
  .dashboard-head .page-head-actions{ width:100%; display:flex; flex-wrap:wrap; gap:8px; }
  .dashboard-head .page-head-actions .btn{ min-height:44px; }
  .dash-strip{ grid-template-columns:repeat(2, minmax(0,1fr)); }
  .dash-stat{ border-bottom:1px solid var(--line); }
  .dash-stat:nth-child(2n){ border-right:none; }
  .dash-stat-value{ font-size:22px; }
  .dp-link, .dp-more{ min-height:44px; }
  .dp-row .btn.small, .dp-icon-btn{ min-height:44px; min-width:44px; }
  .dp-seg-btn{ padding:8px 12px; }
  /* The report is one tap away under Reports; the header keeps to one line. */
  .dp-seg + .dp-link{ display:none; }
}

/* ---------------------------------------------------------------------------
 * Dashboard revamp, fixes from the re-audit (2026-09-30).
 * ------------------------------------------------------------------------- */
/* Chart series colours as their own tokens: a theme that folds green, yellow
   and mustard into one colour (Physare) still tells the series apart. */
:root{ --chart-a:var(--green-dot); --chart-b:var(--yellow-dot); --chart-c:var(--mustard); --chart-d:var(--blue); }
html[data-theme="physare"]{ --chart-a:#E9F26B; --chart-b:#6E6E6B; --chart-c:#F2F2EF; --chart-d:#9CA3AD; }
.dp-bar-fill{ background:var(--chart-a); }
.dp-bar-fill.stage-lead{ background:var(--chart-d); }
.dp-bar-fill.stage-prospect{ background:var(--chart-b); }
.dp-bar-fill.stage-customer{ background:var(--chart-a); }

/* The late pill's ink on a dark theme, as the other tinted badges do. */
html[data-scheme="dark"] .dp-pill.late{ color:#F0B7AE; }

/* Compact tightens the panels again. */
html[data-blocks="compact"] .dp-head{ min-height:38px; padding:5px 12px; }
html[data-blocks="compact"] .dp-title{ font-size:15px; }
html[data-blocks="compact"] .dp-row{ min-height:36px; padding:4px 12px; }
html[data-blocks="compact"] .dp-more{ padding:6px 12px; }
html[data-blocks="compact"] .dp-chart{ height:180px; padding:8px 10px 4px; }
html[data-blocks="compact"] .dash-stat{ padding:8px 12px; }
html[data-blocks="compact"] .dash-stat-value{ font-size:22px; }
html[data-blocks="compact"] .dash-strip{ margin-bottom:14px; }

/* A panel's header stays one line: in a narrow panel the quiet sub-text goes first. */
.dp{ container-type:inline-size; }
.dp-head{ flex-wrap:nowrap; }
.dp-title{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }
.dp-sub{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }
@container (max-width:460px){ .dp-head .dp-sub{ display:none; } }
@container (max-width:300px){ .dp-head .dp-link{ display:none; } }

/* On a phone the page's own search is in the menu, so the first figures sit higher. */
@media (max-width:759px){
  .dashboard-head .gs-wrap, .dashboard-date{ display:none; }
  .dashboard-head{ margin-bottom:12px; }
  .dash-stat{ padding:10px 14px; }
}

/* A short panel ends at its content (2026-09-30, Nick): in a row beside a taller
   one it no longer stretches into blank space. Customised layouts already fit
   each panel to its content unless its height was set by hand. */
.dashboard-grid:not(.is-free){ align-items:start; }

/* A chart in a panel sized by hand fills the height it was given, rather than
   keeping its own 210px and being cut off (or leaving a gap). The body stops
   scrolling for a chart: the chart shrinks instead, down to the panel's minRows. */
.dashboard-grid.is-free > .dashboard-section:not(.is-fit) > .dash-panel-body:has(.dp-chart){ display:flex; flex-direction:column; overflow:hidden; }
.dashboard-grid.is-free > .dashboard-section:not(.is-fit) > .dash-panel-body > .dp:has(.dp-chart){ flex:1 1 auto; min-height:0; }
.dashboard-grid.is-free > .dashboard-section:not(.is-fit) .dp-chart{ flex:1 1 0; height:auto; min-height:110px; }

/* Customize: how many rows a list panel shows, beside Hide. */
.dash-rows{ display:inline-flex; align-items:center; gap:5px; font-size:12px; color:var(--ink-soft); white-space:nowrap; }
.dash-rows select{ font-size:12px; padding:3px 6px; min-height:28px; }
@media (max-width:759px){ .dash-rows select{ min-height:36px; } }
/* Customize: Show, which kinds of item a panel lists. Opens as a row of ticks
   under the bar (never a popover, which the panel's overflow would clip). */
.dash-controls:has(.dash-pick[open]){ flex-wrap:wrap; }
.dash-pick{ font-size:12px; color:var(--ink-soft); }
.dash-pick > summary{ cursor:pointer; list-style:none; padding:4px 9px; border:1px solid var(--line-strong); border-radius:6px; white-space:nowrap; }
.dash-pick > summary::-webkit-details-marker{ display:none; }
.dash-pick > summary::after{ content:" \25BE"; }
.dash-pick[open]{ flex-basis:100%; order:10; }
.dash-pick[open] > summary{ display:inline-block; margin-bottom:6px; background:var(--subtle-bg); color:var(--ink); }
.dash-pick-menu{ display:flex; flex-wrap:wrap; gap:6px 14px; }
.dash-pick-menu .inline-checkbox{ display:inline-flex; align-items:center; gap:6px; min-height:28px; color:var(--ink); }
@media (max-width:759px){ .dash-pick > summary, .dash-pick-menu .inline-checkbox{ min-height:44px; display:inline-flex; align-items:center; } }
/* A quarter-width panel's bar keeps its title: the size shows while dragging anyway. */
.dashboard-section[data-w="3"] .dash-size-readout, .dashboard-section[data-w="4"] .dash-size-readout{ display:none; }
/* A narrow panel's bar wraps rather than squeezing its title to a letter:
   the title takes what is left of the first line, the controls follow. */
.dashboard-grid.is-editing .dash-controls{ flex-wrap:wrap; row-gap:6px; }
.dashboard-grid.is-editing .dash-title{ flex:1 1 90px; }

/* ---------------------------------------------------------------------------
 * Needs attention (2026-09-30): every module warning as a row, urgent first,
 * two columns; muted business-wide in Settings > Business, hidden per person
 * in Customize.
 * ------------------------------------------------------------------------- */
.dp-pill.soon{ background:var(--blue-soft); color:var(--blue-ink, var(--ink)); }
.dp-attn-note{ margin-left:auto; }
.dp-attn-grid{ display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); }
.dp-attn-row{ display:flex; align-items:center; gap:6px; min-width:0; border-bottom:1px solid var(--line); padding-right:10px; }
.dp-attn-row:nth-child(odd){ border-right:1px solid var(--line); }
.dp-attn-go{ flex:1; min-width:0; display:flex; align-items:center; gap:10px; min-height:44px; padding:7px 6px 7px 16px; border:none; background:none; font:inherit; font-size:13px; color:var(--ink); text-align:left; cursor:pointer; }
.dp-attn-go:hover{ background:var(--subtle-bg); }
.dp-attn-count{ min-width:26px; text-align:center; padding:2px 7px; border-radius:6px; font-weight:600; font-size:12px; font-variant-numeric:tabular-nums; }
.dp-attn-count.late{ background:var(--brick-soft); color:#8C332E; }
.dp-attn-count.soon{ background:var(--blue-soft); color:var(--blue-ink, var(--ink)); }
html[data-scheme="dark"] .dp-attn-count.late{ color:#F0B7AE; }
.dp-attn-text{ flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dp-attn-chev{ color:var(--text-muted); font-size:15px; }
.dp-attn-hide{ flex:none; font:inherit; font-size:12px; padding:4px 10px; min-height:30px; border:1px solid var(--line-strong); border-radius:var(--radius); background:var(--paper-raised); color:var(--ink); cursor:pointer; }
.dp-attn-row.is-hidden .dp-attn-go{ opacity:.45; }
/* In Customize a panel's contents go inert; these two switches are the exception. */
.dashboard-grid.is-editing .dp-attn-hide{ pointer-events:auto; }
@media (max-width:759px){
  .dp-attn-grid{ grid-template-columns:minmax(0,1fr); }
  .dp-attn-row:nth-child(odd){ border-right:none; }
  .dp-attn-note{ display:none; }
}

/* Settings > Business > Dashboard warnings. */
.dash-warn-group{ font-size:11px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--ink-soft); margin:12px 0 4px; }
.dash-warn-row{ display:flex; align-items:center; gap:10px; min-height:40px; padding:4px 0; border-bottom:1px solid var(--line); font-size:13px; cursor:pointer; }
.dash-warn-row > span:first-child{ flex:1; }
.dash-warn-off{ font-size:12px; color:var(--ink-soft); }
.dash-warn-switch{ appearance:none; -webkit-appearance:none; width:36px; height:20px; border-radius:10px; background:var(--line-strong); position:relative; cursor:pointer; flex:none; transition:background .15s; padding:0; border:none; }
.dash-warn-switch::after{ content:''; position:absolute; top:2px; left:2px; width:16px; height:16px; border-radius:50%; background:#fff; transition:left .15s; box-shadow:0 1px 2px rgba(0,0,0,.2); }
.dash-warn-switch:checked{ background:var(--green-dot); }
.dash-warn-switch:checked::after{ left:18px; }
.dash-warn-switch:focus-visible{ outline:2px solid var(--mustard); outline-offset:2px; }
.dash-warn-switch:disabled{ opacity:.5; cursor:default; }

/* ---------------------------------------------------------------------------
 * Trends, targets and the sales team (2026-09-30).
 * ------------------------------------------------------------------------- */
/* A target's progress: a thin bar and a line of words, under a chart or in a row. */
.dp-trend-foot:empty{ display:none; }
.dp-target{ display:flex; align-items:center; gap:10px; padding:4px 16px 14px; font-size:12px; color:var(--ink-soft); }
.dp-target-track{ display:block; flex:0 0 180px; height:6px; border-radius:3px; background:var(--subtle-bg); overflow:hidden; }
.dp-target-fill{ display:block; height:100%; border-radius:3px; background:var(--chart-a); }
.dp-target.is-reached .dp-target-text{ color:var(--sage-ink, var(--ink)); font-weight:600; }
.dp-target-text{ min-width:0; }
/* A chart panel with a foot: the chart keeps what is left once the foot is drawn. */
.dashboard-grid.is-free > .dashboard-section:not(.is-fit) > .dash-panel-body > .dp:has(.dp-chart) > .dp-trend-foot{ flex:none; }
@media (max-width:759px){
  .dp-target{ flex-wrap:wrap; }
  .dp-target-track{ flex-basis:100%; }
}

/* Twelve weeks under a count tile. */
.dash-spark{ display:block; width:100%; height:28px; margin-top:4px; overflow:visible; }
.dash-spark polyline{ fill:none; stroke:var(--chart-a); stroke-width:1.6; vector-effect:non-scaling-stroke; }
.dash-spark-sub{ font-size:12px; color:var(--ink-soft); }

/* The target form: the shape as two radios on one line. */
.target-form .field-label{ display:block; font-size:12px; font-weight:600; color:var(--ink-soft); margin-bottom:6px; }
.target-form .seg-radio{ display:flex; gap:18px; flex-wrap:wrap; }
.target-form .seg-radio .inline-checkbox{ display:inline-flex; align-items:center; gap:6px; min-height:32px; }
.target-form [hidden]{ display:none; }
@media (max-width:759px){ .target-form .seg-radio .inline-checkbox{ min-height:44px; } }

/* Settings > Business > Targets. */
.targets-list{ display:flex; flex-direction:column; margin:10px 0 12px; border-top:1px solid var(--line); }
.targets-row{ display:grid; grid-template-columns:minmax(0,1.2fr) minmax(0,1fr) minmax(0,1.4fr) 48px auto; align-items:center; gap:10px; padding:8px 0; border-bottom:1px solid var(--line); font-size:13px; }
.targets-who{ color:var(--ink-soft); }
.targets-pct{ font-variant-numeric:tabular-nums; color:var(--ink-soft); text-align:right; }
.targets-pct.is-reached{ color:var(--sage-ink, var(--ink)); font-weight:600; }
@media (max-width:559px){
  .targets-row{ grid-template-columns:minmax(0,1fr) auto; }
  .targets-who, .targets-amount{ grid-column:1; font-size:12px; }
  .targets-pct{ grid-row:1; grid-column:2; }
  .targets-row .btn{ grid-column:2; min-height:44px; }
}

/* The rep board: a name, the numbers in columns, the target as a bar. */
.dp-reps .dp-row{ gap:12px; }
.dp-rep-head{ min-height:32px; padding-top:6px; padding-bottom:6px; font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--ink-soft); }
.dp-rep-name{ flex:1 1 auto; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dp-rep-num{ flex:0 0 72px; text-align:right; font-variant-numeric:tabular-nums; }
.dp-rep-head .dp-rep-num{ font-variant-numeric:normal; }
.dp-rep-goal{ flex:0 0 150px; display:flex; justify-content:flex-end; }
.dp-row.is-me .dp-rep-name{ font-weight:600; }
.dp-rep-unclaimed{ color:var(--ink-soft); }
.dp-rep-target{ display:inline-flex; align-items:center; gap:8px; width:100%; }
.dp-rep-target .dp-target-track{ flex:1 1 auto; }
.dp-rep-pct{ flex:none; width:38px; text-align:right; font-size:12px; color:var(--ink-soft); font-variant-numeric:tabular-nums; }
.dp-rep-target.is-reached .dp-rep-pct{ color:var(--sage-ink, var(--ink)); font-weight:600; }
@media (max-width:759px){
  .dp-rep-num{ flex-basis:56px; }
  .dp-rep-goal{ flex-basis:88px; }
  .dp-rep-num:nth-of-type(3){ display:none; }
}
/* Claimed accounts: one bar a rep, split by stage. */
.dp-claims-track{ display:flex; gap:2px; height:12px; border-radius:6px; overflow:hidden; background:var(--subtle-bg); }
.dp-claims-track .dp-stack-seg{ min-width:3px; }
/* My book: three figures side by side, the target under them. */
.dp-book{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:10px; padding:14px 16px 10px; }
.dp-book-fig{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.dp-book-label{ font-size:12px; color:var(--ink-soft); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dp-book-value{ font-family:var(--font-display); font-size:22px; font-weight:600; font-variant-numeric:tabular-nums; }
.dp-book-target .dp-target-track{ flex:1 1 auto; }
.dp-book-none{ padding-top:4px; }
/* ---------------------------------------------------------------------------
 * Dashboard presets (2026-09-30): View in the header, the notice over
 * Customize, Settings > Business > Dashboard presets and its form.
 * ------------------------------------------------------------------------- */
.dash-view{ position:relative; }
.dash-view > summary{ list-style:none; cursor:pointer; display:inline-flex; align-items:center; gap:6px; white-space:nowrap; }
.dash-view > summary::-webkit-details-marker{ display:none; }
.dash-view > summary::after{ content:"\25BE"; font-size:11px; color:var(--ink-soft); }
.dash-view > summary .ic{ width:15px; height:15px; margin:0; }
.dash-view-menu{ position:absolute; right:0; top:calc(100% + 6px); z-index:60; min-width:250px; max-width:min(320px, 90vw); padding:6px;
  background:var(--paper-raised); border:1px solid var(--line-strong); border-radius:10px; box-shadow:0 8px 24px rgba(0,0,0,0.14); }
.dash-view-head{ padding:6px 10px 2px; font-size:11px; font-weight:600; letter-spacing:.05em; text-transform:uppercase; color:var(--ink-soft); }
.dash-view-item{ display:flex; align-items:center; gap:8px; width:100%; min-height:36px; padding:6px 10px; font:inherit; font-size:13px; text-align:left;
  color:var(--ink); background:none; border:none; border-radius:6px; cursor:pointer; }
.dash-view-item:hover, .dash-view-item.on{ background:var(--subtle-bg); }
.dash-view-check{ width:14px; flex:none; color:var(--ink); }
.dash-view-note{ margin-left:auto; font-size:11px; color:var(--ink-soft); }
/* A closed menu takes no room at all: its hidden list still widened a phone's page. */
.dash-view:not([open]) > .dash-view-menu{ display:none; }
@media (max-width:759px){
  .dash-view > summary, .dash-view-item{ min-height:44px; }
  /* The button sits at the right of the row on a phone, so the list opens leftwards. */
  .dash-view-menu{ left:auto; right:0; }
}
.dash-edit-notice{ display:flex; align-items:center; gap:6px 12px; flex-wrap:wrap; margin:-4px 0 10px; padding:9px 14px; border-radius:var(--panel-radius);
  background:var(--subtle-bg); font-size:13px; color:var(--ink-soft); }
.dash-edit-notice strong{ color:var(--ink); }
.dash-edit-notice.is-preset{ border:1.5px dashed var(--line-strong); background:transparent; }
.presets-list{ display:flex; flex-direction:column; margin:10px 0 12px; border-top:1px solid var(--line); }
.presets-row{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.6fr) 80px auto; align-items:center; gap:10px; padding:9px 0; border-bottom:1px solid var(--line); font-size:13px; }
.presets-name{ font-weight:600; }
.presets-chip{ display:inline-block; font-size:11px; padding:1px 8px; margin:0 4px 3px 0; border-radius:10px; background:var(--subtle-bg); color:var(--ink-soft); }
.presets-chip.is-default{ background:var(--sage-soft, var(--subtle-bg)); color:var(--sage-ink, var(--ink)); font-weight:600; }
.presets-following{ font-size:12px; color:var(--ink-soft); }
.presets-actions{ display:flex; gap:6px; }
@media (max-width:559px){
  .presets-row{ grid-template-columns:minmax(0,1fr) auto; }
  .presets-roles, .presets-following{ grid-column:1; }
  .presets-actions{ grid-column:2; grid-row:1 / span 3; flex-direction:column; }
  .presets-actions .btn{ min-height:44px; }
}
.preset-role-row{ display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; padding:6px 0; border-bottom:1px solid var(--line); }
.preset-role-row .inline-checkbox{ display:inline-flex; align-items:center; gap:6px; min-height:32px; font-size:13px; }
.preset-default{ color:var(--ink-soft); }
.form-grid .field-label{ display:block; font-size:12px; font-weight:600; color:var(--ink-soft); margin-bottom:6px; }

/* ---------------------------------------------------------------------------
 * Chart headlines and the bars or line switch (2026-09-30).
 * ------------------------------------------------------------------------- */
/* Several switches in one header sit together on the right, not spread across it. */
.dp-head .dp-seg + .dp-seg{ margin-left:6px; }
.dp-seg[hidden]{ display:none; }
.dp-chart-seg .dp-seg-btn{ display:inline-flex; align-items:center; justify-content:center; min-width:30px; }
.dp-chart-seg .ic{ width:15px; height:15px; margin:0; }
.dp-proj.on{ color:var(--ink); }
/* The big figure over a chart, and how it compares. */
.dp-headline{ padding:12px 16px 0; }
.dp-headline-row{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.dp-big{ font-family:var(--font-display); font-size:28px; font-weight:600; line-height:1.15; font-variant-numeric:tabular-nums; color:var(--ink); }
.dp-change{ display:inline-flex; align-items:center; gap:2px; font-size:12px; font-weight:600; padding:2px 8px; border-radius:20px; white-space:nowrap; background:var(--subtle-bg); color:var(--ink-soft); }
.dp-change.up{ background:var(--sage-soft); color:var(--sage-ink, var(--ink)); }
.dp-change.down{ background:var(--brick-soft); color:#8C332E; }
html[data-scheme="dark"] .dp-change.down{ color:#F0C4BE; }
.dp-caption{ margin-top:2px; font-size:12px; color:var(--ink-soft); }
/* A chart panel with a headline: the chart keeps what is left once it is drawn. */
.dashboard-grid.is-free > .dashboard-section:not(.is-fit) > .dash-panel-body > .dp:has(.dp-chart) > .dp-headline,
.dashboard-grid.is-free > .dashboard-section:not(.is-fit) > .dash-panel-body > .dp:has(.dp-chart) > #dash-sales-headline,
.dashboard-grid.is-free > .dashboard-section:not(.is-fit) > .dash-panel-body > .dp:has(.dp-chart) > .dp-trend-headline{ flex:none; }
@media (max-width:759px){
  .dp-big{ font-size:24px; }
  .dp-chart-seg .dp-seg-btn{ min-width:44px; }
}
/* Outside a panel header the switches keep their own place. */
.report-chart-tools .dp-seg, .sales-chart-type .dp-seg{ margin-left:0; }
/* A switch never shrinks to a sliver; in a narrow panel (a phone, half width) a chart's
   header gives the title its own line and the switches the next, rather than one line. */
.dp-seg{ flex:none; }
@container (max-width:600px){
  .dp-head:has(.dp-chart-seg){ flex-wrap:wrap; row-gap:8px; }
  .dp-head:has(.dp-chart-seg) .dp-title{ flex:1 0 100%; }
  .dp-head:has(.dp-chart-seg) .dp-seg:first-of-type{ margin-left:0; }
}

/* The menu scrolls on its own (2026-09-30): on a desktop it is the screen's height and
   keeps its place, so the wheel over it moves the menu and never the page behind it. */
@media (min-width:821px){
  .rail{ position:sticky; top:0; align-self:start; height:100vh; overflow-y:auto; overscroll-behavior:contain; scrollbar-width:thin; }
  html.rail-collapsed .rail{ overflow-x:hidden; overflow-y:auto; }
  /* The mark, the bell and the three lines stay at the top while the menu scrolls
     beneath them (Nick, 2026-10-19). The negative margin and matching padding keep
     the block where it sits, so it never jumps when it starts to stick. */
  .rail > .brand{ position:sticky; top:-28px; z-index:3; margin-top:-28px; padding-top:28px; padding-bottom:12px; background:var(--paper); }
  html.rail-collapsed .rail > .brand{ top:-24px; margin-top:-24px; padding-top:24px; }
}

/* The range as a dropdown in a chart's header (2026-09-30, Nick's reference). */
.dp-range{ margin-left:auto; flex:none; font:inherit; font-size:12px; color:var(--ink); min-height:30px; padding:4px 26px 4px 10px;
  border:1px solid var(--line-strong); border-radius:8px; background-color:var(--paper-raised); cursor:pointer; }
.dp-head .dp-range + .dp-seg{ margin-left:6px; }
@container (max-width:600px){ .dp-head:has(.dp-chart-seg) .dp-range{ margin-left:0; } }
@media (max-width:759px){ .dp-range{ min-height:44px; font-size:14px; } }/* No visible scrollbar on the menu, like the app dock beside it: it still scrolls by wheel, touch and keys. */
@media (min-width:821px){
  .rail{ scrollbar-width:none; }
  .rail::-webkit-scrollbar{ display:none; }
}

/* Five line colours for a comparison chart (Sales by rep), the same in every theme
   so no two reps share a hue, lightened on a dark scheme. */
:root{ --race-1:#3F7D52; --race-2:#2F6FB3; --race-3:#C2562B; --race-4:#7A5BC4; --race-5:#A87510; }
/* Activity's kinds: the race colours unless a theme says otherwise. */
:root{ --act-email:var(--race-2); --act-call:var(--race-1); --act-visit:var(--race-3); --act-note:var(--line-strong); }
/* A stat's history (dashStatSparkHtml): a curve in the corner of its cell, a dot on today. */
.dash-stat-spark{ position:absolute; top:12px; right:14px; width:64px; height:26px; overflow:visible; pointer-events:none; }
.dash-stat-spark path{ fill:none; stroke:var(--sage); stroke-opacity:0.6; stroke-width:2; stroke-linecap:round; }
.dash-stat-spark circle{ fill:var(--sage-ink, var(--ink)); stroke:var(--panel-bg, #fff); stroke-width:1.5; }
.dash-stat-spark.late path{ stroke:var(--brick); stroke-opacity:0.45; }
.dash-stat-spark.late circle{ fill:var(--brick); }
.dash-stat:has(.dash-stat-spark) .dash-stat-label{ padding-right:72px; }
/* Customising: the remove button takes that corner, so the curve steps aside. */
.dash-stat:has(.dash-stat-remove) .dash-stat-spark{ display:none; }
/* On a phone the cells are narrow: the curve moves down beside the figure, so the label keeps its line. */
@media (max-width:759px){
  .dash-stat-spark{ top:auto; bottom:12px; right:10px; width:44px; height:22px; }
  .dash-stat:has(.dash-stat-spark) .dash-stat-label{ padding-right:0; }
}
/* The cadence step's Log button: the word here, a round play button in the Grainpath look. */
.cad-go-ic{ display:none; }
html[data-scheme="dark"]{ --race-1:#6FB884; --race-2:#6AA4E6; --race-3:#E58A63; --race-4:#A58EE6; --race-5:#D6A63E; }
/* ---------------------------------------------------------------------------
 * Phone fixes from the dashboard audit, round 4 (2026-09-30).
 * ------------------------------------------------------------------------- */
/* 16px inputs on a phone: anything smaller and iOS zooms the page when one is tapped. */
@media (max-width:759px){
  .dp-range, .race-team, .dash-rows select, .dash-stat-add select, .gs-wrap input, .dash-pick-menu input{ font-size:16px; }
}
/* A finger's worth (44px) for every control on the dashboard. */
@media (pointer:coarse){
  .dp-seg-btn{ min-height:44px; min-width:44px; }
  .dp-link, .dp-more, .race-reset, .race-link{ min-height:44px; }
  .dash-hot-chip button{ width:44px; height:44px; }
  .dp-bar-row{ min-height:44px; }
  .cal-week-more{ min-height:44px; }
  .dash-view > summary, .dash-view-item{ min-height:44px; }
}
/* My book: a label wraps to a second line rather than losing its end ("Sales this mo..."). */
.dp-book-label{ white-space:normal; overflow:visible; text-overflow:clip; line-height:1.3; }
/* Customize on a phone: the remove button no longer sits on the stat's name, and Add a stat takes the whole row. */
@media (max-width:759px){
  .dash-strip .dash-stat:has(.dash-stat-remove){ padding-right:48px; }
  .dash-stat-remove{ width:36px; height:36px; top:4px; right:4px; }
  .dash-strip .dash-stat-add{ grid-column:1 / -1; }
}
/* A chart header that wraps: the second row starts flush, no stray indent before a switch. */
@container (max-width:600px){ .dp-head .dp-seg + .dp-seg, .dp-head .dp-range + .dp-seg{ margin-left:0; } }

/* ---------------------------------------------------------------------------
 * Dashboard audit round 4, the rest (2026-09-30).
 * ------------------------------------------------------------------------- */
/* 1. A narrow panel keeps its time period ("this month", "next 14 days") and drops the
      report link instead: the report is one click away in the menu. */
@container (max-width:460px){
  .dp-head .dp-sub{ display:inline; }
  .dp-head:has(.dp-sub) .dp-link{ display:none; }
}
/* 7. A chart header that has to wrap does so naturally (title first, controls as they fit),
      the report link goes, and Projection is its icon alone. */
@container (max-width:600px){
  .dp-head:has(.dp-chart-seg) .dp-title{ flex:0 0 auto; }
  .dp-head:has(.dp-chart-seg) .dp-link{ display:none; }
  .dp-proj-text{ display:none; }
}
.dp-proj{ display:inline-flex; align-items:center; gap:6px; }
.dp-proj .ic{ width:15px; height:15px; margin:0; }
.dp-proj:disabled{ opacity:.45; cursor:default; }
/* 4. The menu says there is more below it with a fade at its bottom edge. */
@media (min-width:821px){
  .rail.has-more{ -webkit-mask-image:linear-gradient(to bottom, #000 calc(100% - 32px), transparent); mask-image:linear-gradient(to bottom, #000 calc(100% - 32px), transparent); }
}
/* Customize: a panel's bar no longer names it over its own title; tiles, which have none, keep it. */
.dashboard-grid.is-editing .dashboard-section:has(.dp-title) > .dash-controls .dash-title{ display:none; }
/* The rep leaderboard's names take the spare width; Target narrows to what it shows. */
.dp-rep-goal{ flex:0 1 150px; min-width:84px; }
/* The phone's first screen: the hot buttons and Customize on one row, a slimmer stat strip. */
@media (max-width:759px){
  .dashboard-head .page-head-actions{ flex-wrap:nowrap; }
  .dashboard-head .page-head-actions > .btn{ flex:1 1 0; min-width:0; padding:0 8px; font-size:14px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .dashboard-head .page-head-actions > .btn.icon-only, .dashboard-head .page-head-actions > .dash-view{ flex:none; }
  /* View is its icon alone here: "View: My own" made the row wider than the phone, and the
     whole page zoomed out to fit it. The menu it opens still names every choice. */
  .dashboard-head .dash-view > summary{ font-size:0; gap:4px; padding:0 10px; }
  .dash-stat{ padding:8px 12px; }
  .dash-stat-value{ font-size:20px; }
  .dash-stat-sub{ display:none; }
}/* The rep leaderboard in a narrow panel: names first; "New" goes and the figures narrow. */
@container (max-width:560px){
  .dp-reps .dp-rep-num{ flex-basis:58px; }
  .dp-reps .dp-rep-num:nth-of-type(3){ display:none; }
  .dp-reps .dp-rep-goal{ flex-basis:96px; min-width:72px; }
}

/* The legend as the picker, for every comparison chart (Sales by rep, Activity): shared here so it draws with any module off. */
.race-status{ display:flex; align-items:center; gap:10px; padding:10px 16px 0; font-size:12px; color:var(--ink-soft); }
.race-reset, .race-link{ font:inherit; font-size:12px; color:var(--ink); background:none; border:none; padding:4px 0; text-decoration:underline; cursor:pointer; }
.race-chips{ display:flex; flex-wrap:wrap; gap:6px; padding:8px 16px 4px; }
.race-chip{ display:inline-flex; align-items:center; gap:6px; min-height:30px; padding:2px 4px 2px 10px; border:1px solid var(--line); border-radius:16px; font-size:12px; background:var(--paper-raised); }
.race-swatch{ display:inline-block; width:12px; height:3px; border-radius:2px; flex:none; }
.race-chip-name{ color:var(--ink); max-width:140px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.race-chip-total{ color:var(--ink-soft); font-variant-numeric:tabular-nums; }
.race-chip-x{ width:24px; height:24px; border:none; border-radius:50%; background:none; color:var(--ink-soft); font-size:15px; line-height:1; cursor:pointer; }
.race-chip-x:hover{ background:var(--subtle-bg); color:var(--ink); }
.race-add{ min-height:30px; padding:2px 12px; border:1px dashed var(--line-strong); border-radius:16px; background:none; font:inherit; font-size:12px; color:var(--ink); cursor:pointer; }
.race-add-count{ color:var(--ink-soft); }
.race-add-panel{ margin:6px 16px 4px; padding:10px 12px; border:1px solid var(--line-strong); border-radius:10px; background:var(--paper-raised); }
.race-add-head{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.race-add-head .dp-seg{ margin-left:0; }
.race-team{ font:inherit; font-size:12px; min-height:30px; padding:3px 8px; border:1px solid var(--line-strong); border-radius:8px; background:var(--paper-raised); color:var(--ink); }
.race-pick-list{ display:grid; grid-template-columns:repeat(auto-fill, minmax(150px, 1fr)); gap:2px 12px; margin:8px 0; max-height:180px; overflow:auto; }
.race-pick{ display:flex; align-items:center; gap:6px; min-height:30px; font-size:13px; }
.race-add-foot{ display:flex; align-items:center; gap:8px; justify-content:flex-end; flex-wrap:wrap; }
.race-note{ margin-right:auto; font-size:12px; color:var(--ink-soft); }
.race-unclaimed{ margin:0; padding:2px 16px 12px; font-size:12px; color:var(--ink-soft); }
@media (max-width:759px){
  .race-chip, .race-add, .race-pick, .race-team{ min-height:44px; }
  .race-chip-x{ width:36px; height:36px; }
  .race-team{ font-size:16px; }
}

/* Scan boxes (2026-10-01): a scanner, typing, or the camera. */
.scan-box{ display:flex; gap:8px; align-items:center; }
.scan-box .scan-input{ flex:1 1 auto; min-width:0; }
.scan-box .scan-camera-btn{ flex:none; }
.scan-status{ min-height:16px; margin-top:4px; }
.scan-status.bad{ color:var(--brick); }
.scan-camera-overlay{ position:fixed; inset:0; z-index:2000; background:rgba(0,0,0,.6); display:flex; align-items:center; justify-content:center; padding:16px; }
.scan-camera-panel{ background:var(--paper-raised); border-radius:10px; padding:14px; width:min(480px, 100%); }
.scan-camera-head{ display:flex; justify-content:space-between; align-items:center; gap:8px; margin-bottom:10px; }
.scan-camera-view{ width:100%; min-height:200px; background:#000; border-radius:6px; overflow:hidden; }
.scan-camera-view video{ width:100%; display:block; }
/* ---------------------------------------------------------------------------
 * Organization (2026-10-18): the chart drawn from who reports to whom, a box per
 * person with the team as a coloured label, and the people picker (a search box
 * with chips) used for members and managers.
 * ------------------------------------------------------------------------- */
.org-tree{ overflow-x:auto; padding:4px 0 8px; }
/* Siblings are spaced by their own padding, not a flex gap, so the line across them has no breaks. */
.org-tree ul{ position:relative; display:flex; justify-content:center; padding:16px 0 0; margin:0; list-style:none; }
.org-tree li{ position:relative; display:flex; flex-direction:column; align-items:center; padding:16px 5px 0; }
.org-tree li::before, .org-tree ul ul::before{ content:""; position:absolute; top:0; left:50%; height:16px; border-left:1px solid var(--line-strong, var(--line)); }
.org-tree ul > li::after{ content:""; position:absolute; top:0; left:0; right:0; border-top:1px solid var(--line-strong, var(--line)); }
.org-tree ul > li:first-child::after{ left:50%; }
.org-tree ul > li:last-child::after{ right:50%; }
.org-tree ul > li:only-child::after{ display:none; }
.org-tree > ul.org-roots{ padding-top:0; gap:28px; }
.org-tree > ul.org-roots > li{ padding-top:0; }
.org-tree > ul.org-roots > li::before, .org-tree > ul.org-roots > li::after{ display:none; }
.org-card{ background:var(--paper-raised); border:1px solid var(--line); border-radius:10px; padding:8px 10px; width:140px; text-align:center; cursor:pointer; }
.org-card:hover, .org-card:focus-visible{ border-color:var(--line-strong, var(--ink-soft)); outline:none; }
.org-card.hit{ border:2px solid var(--blue); padding:7px 9px; }
.org-name{ font-size:13px; font-weight:600; line-height:1.3; }
.org-title{ font-size:11px; color:var(--ink-soft); line-height:1.3; }
.org-tag{ display:inline-block; font-size:11px; padding:1px 8px; border-radius:999px; margin-top:5px; }
.org-kids{ display:block; margin:5px auto 0; border:0; background:transparent; font:inherit; font-size:11px; color:var(--ink-soft); cursor:pointer; padding:2px 4px; border-radius:4px; }
.org-kids:hover{ background:var(--subtle-bg); }
.org-loose{ cursor:pointer; border:0; font:inherit; }
.org-plan{ margin:4px 0 0; padding-left:18px; font-size:13px; line-height:1.6; }
.org-plan-log{ color:var(--ink-soft); }
.org-pick{ position:relative; }
.org-pick-box{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; border:1px solid var(--line); border-radius:6px; padding:4px 8px; min-height:38px; background:var(--paper-raised); cursor:text; }
.org-pick-box:focus-within{ border-color:var(--ink-soft); }
.org-pick-box .ic{ color:var(--ink-soft); flex:none; }
.org-pick-box input{ border:0; flex:1; min-width:140px; height:28px; background:transparent; padding:0; box-shadow:none; outline:none; }
.org-pick-chips{ display:contents; }
.org-chip{ display:inline-flex; align-items:center; gap:4px; font-size:12px; padding:2px 4px 2px 10px; border-radius:999px; background:var(--blue-soft); color:var(--blue-ink); }
.org-chip button{ border:0; background:transparent; color:inherit; font-size:14px; line-height:1; width:20px; height:20px; padding:0; cursor:pointer; border-radius:50%; }
/* In the flow of the dialog, never over it: an open list must not cover Save. */
.org-pick-list{ margin-top:4px; background:var(--paper-raised); border:1px solid var(--line); border-radius:6px; padding:4px; max-height:220px; overflow:auto; }
.org-pick-opt{ display:flex; align-items:center; gap:10px; padding:6px 8px; border-radius:5px; cursor:pointer; }
.org-pick-opt.act, .org-pick-opt:hover{ background:var(--subtle-bg); }
.org-pick-move{ font-size:11px; padding:2px 8px; border-radius:999px; background:var(--mustard-soft); color:var(--mustard-ink); white-space:nowrap; }
.org-av{ width:28px; height:28px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font-size:11px; font-weight:600; background:var(--subtle-bg); color:var(--ink-soft); flex:none; }
.org-member-rows{ border-top:1px solid var(--line); max-height:40vh; overflow-y:auto; }
.org-member-row{ display:flex; align-items:center; gap:10px; padding:7px 2px; border-bottom:1px solid var(--line); }
@media (max-width:640px){
  .org-card{ width:118px; }
  .org-pick-box input{ min-width:100px; }
}
/* Print the chart alone (Print on the chart; a browser's print window also saves a PDF). */
@media print{
  html.org-print body *{ visibility:hidden; }
  html.org-print #org-chart, html.org-print #org-chart *{ visibility:visible; }
  html.org-print #org-chart{ position:absolute; left:0; top:0; width:100%; }
  html.org-print .org-tree{ overflow:visible; }
}

/* ---------- saved lists (2026-10-26): the side panel, the open list's head, the builder ---------- */
.sl-work{ display:flex; flex-wrap:wrap; gap:18px; align-items:flex-start; }
.sl-panel{ flex:1 1 230px; max-width:240px; background:var(--panel-bg); border:var(--panel-border); border-radius:var(--panel-radius); box-shadow:var(--panel-shadow); padding:12px 8px; box-sizing:border-box; position:sticky; top:12px; max-height:calc(100vh - 24px); overflow-y:auto; overscroll-behavior:contain; }
.sl-pane{ flex:999 1 560px; min-width:0; }
.sl-ph{ display:flex; align-items:center; justify-content:space-between; padding:0 6px 8px; font-weight:600; font-size:15px; }
.sl-add{ width:30px; height:30px; display:inline-flex; align-items:center; justify-content:center; border:1px solid var(--line-strong); border-radius:8px; background:var(--paper-raised); color:var(--ink); cursor:pointer; }
.sl-add:hover{ border-color:var(--ink); }
.sl-grp{ font-size:10px; letter-spacing:0.12em; text-transform:uppercase; color:var(--text-muted); padding:12px 8px 4px; }
.sl-li{ display:flex; align-items:center; gap:8px; width:100%; padding:7px 8px; border:0; border-radius:8px; background:transparent; font:inherit; font-size:14px; color:var(--ink); text-align:left; cursor:pointer; min-height:36px; }
.sl-li:hover{ background:var(--subtle-bg); }
.sl-li.on{ background:var(--sage-soft); color:var(--sage-ink); font-weight:500; }
.sl-li .sl-name{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sl-n{ font-size:12px; color:var(--text-muted); font-variant-numeric:tabular-nums; }
.sl-li.on .sl-n{ color:var(--sage-ink); }
.sl-k{ width:14px; height:14px; flex:0 0 auto; color:var(--text-muted); }
.sl-empty{ font-size:12px; color:var(--text-muted); padding:10px 8px 2px; margin:0; }
.sl-phone{ display:none; margin-bottom:12px; }
.sl-phone-btn{ display:flex; align-items:center; gap:8px; width:100%; min-height:48px; padding:8px 12px; background:var(--paper-raised); border:1px solid var(--line-strong); border-radius:10px; font:inherit; color:var(--ink); text-align:left; cursor:pointer; }
.sl-phone-txt{ flex:1; min-width:0; line-height:1.25; }
.sl-sheet .sl-li{ min-height:46px; font-size:16px; }
.sl-head{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:4px; }
.sl-title{ font-size:21px; font-weight:600; margin:0; letter-spacing:-0.01em; }
.sl-tag{ font-size:12px; color:var(--ink-soft); background:var(--paper-raised); border:1px solid var(--line); border-radius:999px; padding:3px 10px; }
.sl-spacer{ flex:1; }
.sl-chips{ display:flex; flex-wrap:wrap; gap:6px; align-items:center; margin:8px 0 14px; }
.sl-chip{ font-size:13px; background:var(--mustard-soft); color:var(--mustard-ink); border-radius:999px; padding:4px 11px; }
.sl-chip-none{ font-size:13px; color:var(--text-muted); }
.sl-and{ font-size:12px; color:var(--text-muted); }
.sl-note{ font-size:13px; color:var(--ink-soft); margin:8px 0 14px; }
.sl-more{ position:relative; }
.sl-more > summary{ list-style:none; }
.sl-more > summary::-webkit-details-marker{ display:none; }
.sl-more-menu{ position:absolute; right:0; top:calc(100% + 6px); z-index:20; min-width:220px; background:var(--paper-raised); border:1px solid var(--line); border-radius:12px; box-shadow:0 8px 28px rgba(31,46,39,0.18); padding:6px; display:flex; flex-direction:column; }
.sl-more-menu button{ text-align:left; border:0; background:transparent; font:inherit; font-size:14px; color:var(--ink); padding:9px 10px; border-radius:8px; cursor:pointer; }
.sl-more-menu button:hover{ background:var(--subtle-bg); }
.sl-more-menu button.danger{ color:var(--brick); }
.sl-pick-lists{ display:flex; flex-direction:column; gap:2px; margin-bottom:6px; }
/* the builder */
.sl-sec{ margin:14px 0 8px; }
.sl-group{ border:1px solid var(--line); border-radius:12px; padding:12px 12px 4px; background:var(--subtle-bg); margin-bottom:8px; }
.sl-group.nested{ background:var(--paper-raised); border-color:var(--line-strong); }
.sl-group.related{ margin:0 0 10px 18px; background:var(--mustard-soft); border-color:color-mix(in srgb, var(--mustard) 35%, var(--line)); }
.sl-gh{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; font-size:14px; margin-bottom:10px; }
.sl-gh select{ width:auto; min-width:70px; padding:4px 8px; }
.sl-rule{ display:grid; grid-template-columns:minmax(0,1.25fr) minmax(0,1fr) minmax(0,1.35fr) 34px; gap:8px; align-items:center; margin-bottom:8px; }
.sl-rule select, .sl-rule input{ min-width:0; width:100%; box-sizing:border-box; }
.sl-val{ min-width:0; }
.sl-inline{ display:flex; gap:6px; align-items:center; min-width:0; }
.sl-inline input, .sl-inline select{ flex:1; min-width:0; }
.sl-inline .sl-n-in{ flex:0 0 76px; }
.sl-x{ width:32px; height:32px; border:0; background:transparent; color:var(--text-muted); border-radius:8px; cursor:pointer; display:inline-flex; align-items:center; justify-content:center; }
.sl-x:hover{ background:var(--paper-raised); color:var(--brick); }
.sl-hint{ margin:-4px 0 8px; }
.sl-none{ margin:0 0 6px; }
.sl-adds{ display:flex; gap:16px; margin:2px 0 8px; }
.sl-adds button{ border:0; background:transparent; color:var(--sage-ink); font:inherit; font-weight:500; font-size:13px; padding:4px 0; cursor:pointer; }
.sl-multi{ position:relative; }
.sl-multi > summary{ list-style:none; cursor:pointer; border:1px solid var(--line-strong); border-radius:8px; background:var(--paper-raised); padding:8px 10px; font-size:14px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sl-multi > summary::-webkit-details-marker{ display:none; }
.sl-multi-list{ position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:30; min-width:220px; max-height:260px; overflow-y:auto; background:var(--paper-raised); border:1px solid var(--line); border-radius:10px; box-shadow:0 8px 24px rgba(31,46,39,0.16); padding:6px; }
.sl-check{ display:flex; align-items:center; gap:8px; padding:6px 6px; font-size:14px; cursor:pointer; }
.sl-teams{ display:flex; flex-wrap:wrap; gap:4px 14px; margin-top:8px; }
.sl-seg{ display:inline-flex; border:1px solid var(--line-strong); border-radius:9px; overflow:hidden; background:var(--paper-raised); flex-wrap:wrap; }
.sl-seg button{ border:0; background:transparent; padding:8px 13px; font:inherit; font-size:14px; color:var(--ink-soft); cursor:pointer; }
.sl-seg button.on{ background:var(--gp-forest, var(--ink)); color:#fff; font-weight:500; }
.sl-count{ font-size:14px; color:var(--ink-soft); margin:10px 0 16px; min-height:20px; }
.sl-count strong{ font-size:18px; color:var(--ink); }
@media (max-width:820px){
  .sl-panel{ display:none; }
  .sl-phone{ display:block; }
  .sl-rule{ grid-template-columns:minmax(0,1fr) 34px; }
  .sl-rule > select:not(.sl-field), .sl-rule > .sl-val, .sl-rule > .sl-inline, .sl-rule > span{ grid-column:1; }
  .sl-rule > .sl-x{ grid-column:2; grid-row:1; }
  .sl-group.related{ margin-left:8px; }
}
.dp-sl-n{ font-size:18px; font-weight:600; color:var(--ink); }
.dp-sl-ch{ font-size:12px; color:var(--sage-ink); min-width:40px; text-align:right; }
.dp-sl-ch.up{ color:var(--brick); }
@media (max-width:820px){ .sl-head .sl-title{ display:none; } }
