/* ========================================
   SELF-HOSTED WEBFONTS
   ----------------------------------------
   Lora and DM Sans, served from our own origin instead of fonts.googleapis.com.

   WHY THIS IS NOT A PERFORMANCE TWEAK. Loading a stylesheet from Google and
   the .woff2 files from fonts.gstatic.com sent every visitor's IP address and
   user-agent to Google on every page view, before the cookie banner had been
   answered and whatever the visitor answered. That made Google a sub-processor
   for a font, on a site whose privacy policy is meant to name every company
   that sees anything — so the fix is to stop making the request, not to add a
   row to the table. Nothing on a page load now leaves serochat.ai except the
   analytics the visitor has explicitly accepted.

   The files are the same variable .woff2 subsets Google was serving, downloaded
   from fonts.gstatic.com on 8 September 2026, with Google's own unicode-range
   values preserved verbatim below — so a browser still fetches only the subsets
   the page's characters actually need, and rendering is unchanged.

   LICENCE: both families are SIL Open Font License 1.1, which permits hosting
   them ourselves. The licence text ships beside the files, in
   public/assets/fonts/OFL-DM-Sans.txt and OFL-Lora.txt. Keep those two files
   next to the fonts — the OFL requires the notice to travel with the software.

   Weight ranges are the ones the site asks for, not the full axis of each
   variable file, so a stray font-weight: 700 on Lora synthesises a bold exactly
   as it did when Google served it rather than quietly rendering a new face.

   To add a weight or a family: fetch the css2 URL with a modern browser
   user-agent, download the .woff2 it names into public/assets/fonts/, and add
   the face here with its unicode-range copied across. Do not link
   fonts.googleapis.com back into head.php.
======================================== */

/* latin-ext */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../fonts/dmsans-normal-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../fonts/dmsans-normal-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Lora';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url(../fonts/lora-italic-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Lora';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url(../fonts/lora-italic-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* math */
@font-face {
  font-family: 'Lora';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url(../fonts/lora-italic-math.woff2) format('woff2');
  unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
  font-family: 'Lora';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url(../fonts/lora-italic-symbols.woff2) format('woff2');
  unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
  font-family: 'Lora';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url(../fonts/lora-italic-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Lora';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url(../fonts/lora-italic-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Lora';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url(../fonts/lora-italic-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(../fonts/lora-normal-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(../fonts/lora-normal-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* math */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(../fonts/lora-normal-math.woff2) format('woff2');
  unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(../fonts/lora-normal-symbols.woff2) format('woff2');
  unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(../fonts/lora-normal-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(../fonts/lora-normal-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(../fonts/lora-normal-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ========================================
   SEROCHAT DESIGN TOKENS
   Shared by all pages. Page-specific tokens
   (chat bubbles, hero glow, etc.) stay inline
   in their respective files.
======================================== */

:root {
  /* Brand */
  /* Brand green. Was #1D9E75 in launch v1 — white-on-#1D9E75 computes
     to ~3.0:1 contrast which fails WCAG 2.1 AA (4.5:1 for body text,
     3:1 for large text). #0F6E56 is the deeper end of the same hue and
     reaches ~6.5:1 against white, comfortably AA. The token is reused
     across every layout (marketing CTAs, auth submit, skip-link, status
     dots, accent outlines) so swapping here is the one-shot fix.
     The --green-darker mid-stop and --green-light tint stay unchanged
     — they're used for gradients and pale backgrounds where contrast
     comes from a separately-coloured foreground. */
  --green: #0F6E56;
  --green-darker: #0B5B47;   /* mid-stop in green gradients */
  --green-dark: #0F6E56;     /* deepest brand-green stop (=--green now) */
  --green-light: #E8EFE5;
  --on-green: #ffffff;
  /* Marketing-page accents */
  --ink-deepest: #0D121C;

  /* Secondary accent — used for informational/upsell surfaces, chart depth,
     and "needs attention" cues. Reserves the brand green for primary actions
     and "good/done" states only. Calm dusty plum chosen against the warm
     paper background; close to the editorial serif palette. */
  --plum: #7B5E83;
  --plum-dark: #5C4263;
  --plum-light: #F1EBF3;
  --on-plum: #ffffff;

  /* Information / neutral-emphasis (pre-existed inline as #2F3D55 / #E9ECF2) */
  --info: #3D4E5C;
  --info-light: #E9ECF2;
  --info-dark: #2F3D55;

  /* Green accent on ink surfaces (dark panels, auth visual) — replaces the
     scattered #5ED8A7 / #7DD3AE mints with one value, same in both themes. */
  --green-on-ink: #2CC494;

  /* Text */
  --ink: #1A2B3C;
  --ink-soft: #3D4E5C;
  --ink-muted: #5A6878;

  /* Surfaces */
  --paper: #F5F4F1;
  --paper-warm: #F0EDE6;
  --white: #ffffff;

  /* Borders */
  --border: #E8E6DF;
  --border-soft: #f2f1ec;
  --border-strong: #d0cec7;

  /* Status */
  --red: #E55353;
  --red-light: #FEE2E2;
  --amber: #F59E0B;
  --amber-light: #FEF3C7;
  --amber-text: #92400E;
  --info-light: #E9ECF2;
  --info-dark: #2F3D55;

  /* Effects */
  --shadow-card: 0 1px 2px rgba(26,43,60,0.04), 0 6px 20px rgba(26,43,60,0.05);
  --shadow-float: 0 8px 40px rgba(0,0,0,0.10);
  --shadow-cta: 0 6px 16px rgba(26,43,60,0.14);
  --shadow-cta-hover: 0 10px 24px rgba(26,43,60,0.20);
  --tooltip-bg: #1A2B3C;
  --highlight: #FEF3C7;

  /* Motion */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --ease-out-soft: cubic-bezier(0.16, 1, 0.3, 1);   /* gentle settle — arrivals */
  --ease-in-sharp: cubic-bezier(0.7, 0, 0.84, 0);   /* assertive exit */
  --ease-press: cubic-bezier(0.4, 0, 1, 1);         /* sharp press-down */
  --dur-press: 100ms;
  --dur-modal-in: 220ms;
  --dur-modal-out: 140ms;
  --dur-toast-in: 280ms;
  --dur-toast-out: 200ms;
  --dur-reveal: 600ms;
  --dur-stagger: 80ms;
  --dur-drawer-in: 320ms;
  --dur-tooltip-delay: 300ms;
  --dur-theme: 280ms;
  --scroll-offset: 80px;

  /* Fills — flattened in the de-templating pass. The 135deg gradients read as
     generated SaaS chrome; primary surfaces are now flat brand green with a
     hairline border (see app.css). Token names kept so stragglers stay valid. */
  --gradient-green: var(--green);
  --gradient-green-hover: var(--green-darker);
  --gradient-paper: #F5F4F1; /* flat cream page background; was linear-gradient(#FAF8F4 → #F7F6F2) */

  /* Radii */
  --radius-sm: 10px;
  --radius-md: 14px;
  --radius-card: 20px;
  --radius-pill: 100px;

  /* Typography */
  --font-serif: 'Lora', Georgia, serif;
  --font-sans: 'DM Sans', sans-serif;

  /* Type scale — every text-rendering rule should pick from one of these.
     Picked deliberately to map onto the existing usage clusters
     (12.5–14, 16–18, 22, 28–32, 44+) without producing wildly different
     output, but on a defined ladder so future drift gets caught. */
  --text-xs:    11px;     /* fine print, eyebrows, badge text  */
  --text-sm:    12px;     /* metadata, helper, table-cell text */
  --text-base:  14px;     /* default body                       */
  --text-md:    15px;     /* settings labels, key UI            */
  --text-lg:    16px;     /* primary body, larger UI            */
  --text-xl:    18px;     /* section subhead                    */
  --text-2xl:   22px;     /* card titles                        */
  --text-3xl:   28px;     /* page titles                        */
  --text-4xl:   36px;     /* small marketing display            */
  --text-5xl:   48px;     /* large section display              */
  --text-display: 44px;   /* marketing display                  */
  --text-display-lg: 64px;/* marketing hero (compact)           */
  --text-display-xl: 78px;/* marketing hero                     */
  --text-body-lg: 17px;   /* marketing body prose               */

  --leading-tight:  1.15;
  --leading-snug:   1.3;
  --leading-normal: 1.5;
  --leading-relaxed: 1.65;
  --tracking-tight: -0.02em;
  --tracking-eyebrow: 0.16em;

  /* Spacing scale (4-px base). Inline px in views should drift toward these
     over time. Codemod-friendly: pick the closest token for each value. */
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  20px;
  --space-6:  24px;
  --space-7:  32px;
  --space-8:  40px;
  --space-9:  48px;
  --space-10: 64px;
  --space-11: 80px;
  --space-12: 96px;

  /* Focus ring — single source of truth. Apply with :focus-visible.
     Light bg uses the brand green at 32% alpha; dark theme overrides
     this with the darker-bg variant below. */
  --ring:           0 0 0 3px rgba(15,110,86,0.32);
  --ring-input:     0 0 0 3px rgba(15,110,86,0.18);
  --ring-destructive: 0 0 0 3px rgba(229,83,83,0.32);

  /* Layout (app pages) */
  --sidebar-w: 252px;
  --sidebar-w-collapsed: 76px;

  /* App-page interactions */
  --row-hover: #FAFAF7;
}

[data-theme="dark"] {
  /* Brand */
  --green: #2CC494;
  --green-darker: #27B88C;
  --green-dark: #27B88C;
  --green-light: #143830;
  --on-green: #0E1014;
  --ink-deepest: #0B0D10;

  --green-on-ink: #2CC494;

  /* Secondary accent (dark) */
  --plum: #B695BE;
  --plum-dark: #D9C2DD;
  --plum-light: #2A2230;
  --on-plum: #0E1014;

  /* Information / neutral-emphasis (dark) */
  --info: #B8C2D4;
  --info-light: #1F2632;
  --info-dark: #B8C2D4;

  /* Focus ring — dark variant */
  --ring:           0 0 0 3px rgba(44,196,148,0.40);
  --ring-input:     0 0 0 3px rgba(44,196,148,0.22);
  --ring-destructive: 0 0 0 3px rgba(229,83,83,0.40);

  /* Text */
  --ink: #F2EFE8;
  --ink-soft: #C4BEB2;
  --ink-muted: #8A8477;

  /* Surfaces */
  --paper: #15171C;
  --paper-warm: #1B1E24;
  --white: #1E2127;

  /* Borders */
  --border: #2B2F36;
  --border-soft: #22262C;
  --border-strong: #3B4048;

  /* Status */
  --red: #E55353;
  --red-light: #3D1F1F;
  --amber: #D4841F;
  --amber-light: #3A2912;
  --amber-text: #E0C78B;
  --info-light: #1F2632;
  --info-dark: #B8C2D4;

  /* Effects */
  --shadow-card: 0 1px 2px rgba(0,0,0,0.20), 0 6px 20px rgba(0,0,0,0.25);
  --shadow-float: 0 8px 40px rgba(0,0,0,0.5);
  --shadow-cta: 0 6px 16px rgba(0,0,0,0.30);
  --shadow-cta-hover: 0 10px 24px rgba(0,0,0,0.40);
  --tooltip-bg: #0B0D10;
  --highlight: #3A2912;

  /* Fills — flat (see light-theme note) */
  --gradient-green: var(--green);
  --gradient-green-hover: var(--green-darker);
  --gradient-paper: #181B20; /* flat dark page background */

  /* App-page interactions */
  --row-hover: #22262C;
}

/* Accessibility skip-link — hidden off-screen until keyboard-focused.
   Defined in tokens.css so every layout (marketing, app, auth) gets it
   without needing to load app.css just for this rule. */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  padding: 8px 16px;
  background: var(--green); color: var(--white);
  border-radius: 0 0 8px 0;
  font-size: 14px; font-weight: 500;
  text-decoration: none;
}
.skip-link:focus { left: 0; }

/* Editorial kicker — the single eyebrow grammar for every surface.
   Uppercase DM Sans between two hairlines. Marketing sections centre it;
   app page-headers use the --left variant (trailing hairline only);
   dark panels use --on-ink. Replaces the pill/dot/bare eyebrow variants. */
.sc-kicker {
  display: inline-flex; align-items: center; gap: 14px;
  font-family: var(--font-sans);
  font-size: 12px; font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--green-dark);
}
.sc-kicker::before, .sc-kicker::after {
  content: ''; height: 1px; flex: 0 0 34px;
  background: var(--border-strong);
}
.sc-kicker--left::before { display: none; }
.sc-kicker--on-ink { color: var(--green-on-ink); }
.sc-kicker--on-ink::before, .sc-kicker--on-ink::after { background: rgba(255,255,255,0.28); }
[data-theme="dark"] .sc-kicker { color: var(--green); }

/* ========================================
   PREMIUM MICRO-INTERACTION PRIMITIVES
   Shared by marketing, auth, and app layouts.
   App-only chrome (sidebar, account dropdown)
   stays in app.css.
======================================== */

/* Global box-sizing — every page that loads tokens.css gets border-box so
   nav-inner and other padded containers measure the same width regardless
   of which page-scoped CSS is present. (app.css repeats the same rule for
   app pages; this duplication is intentional and idempotent.) */
*, *::before, *::after { box-sizing: border-box; }

/* Reset body margin so the browser's default 8px doesn't push a sticky
   nav 8px down on pages whose own CSS doesn't run a `*` reset (pricing,
   terms, privacy, etc.). Pages that need explicit body spacing set it
   themselves. */
body { margin: 0; }

/* Sticky-nav offset for hash navigation (marketing pages have a 64px nav).
   Lets every #anchor target land below the nav, not under it.
   scrollbar-gutter: stable reserves the scrollbar space on every page so the
   sticky nav doesn't jump horizontally when navigating between a long page
   (scrollbar present) and a short one (no scrollbar). */
html {
  scroll-padding-top: var(--scroll-offset);
  scrollbar-gutter: stable;
}
section[id], h1[id], h2[id], h3[id], [data-anchor] { scroll-margin-top: var(--scroll-offset); }

/* Theme crossfade — a 280ms class-scoped transition triggered by toggleTheme().
   Scoped to a class so we don't pay the transition cost on every hover. */
html.theme-transitioning,
html.theme-transitioning body,
html.theme-transitioning .sidebar,
html.theme-transitioning .card,
html.theme-transitioning .panel,
html.theme-transitioning .nav,
html.theme-transitioning .m-nav,
html.theme-transitioning .pricing-card,
html.theme-transitioning .why-tile,
html.theme-transitioning .feature-row,
html.theme-transitioning .auth-card,
html.theme-transitioning .modal,
html.theme-transitioning .em-card,
html.theme-transitioning .page-header,
html.theme-transitioning .greeting,
html.theme-transitioning input,
html.theme-transitioning textarea,
html.theme-transitioning select,
html.theme-transitioning button {
  transition: background-color var(--dur-theme) var(--ease-out-soft),
              border-color var(--dur-theme) var(--ease-out-soft),
              color var(--dur-theme) var(--ease-out-soft) !important;
}

/* Press feedback — every primary CTA acknowledges the click before the
   network round-trip lands. Uses transform so :hover lifts compose
   naturally with the press scale. */
.btn-primary, .btn-secondary, .auth-submit,
.bill-cta, .success-cta, .cancel-cta, .hero-cta, .pricing-cta,
button.btn.primary {
  -webkit-tap-highlight-color: transparent;
}
.btn-primary:active:not([disabled]):not(.is-loading),
.btn-secondary:active:not([disabled]):not(.is-loading),
.auth-submit:active:not([disabled]):not(.is-loading),
.bill-cta:active:not([disabled]):not(.is-loading),
.success-cta:active:not([disabled]):not(.is-loading),
.cancel-cta:active:not([disabled]):not(.is-loading),
.hero-cta:active:not([disabled]):not(.is-loading),
.pricing-cta:active:not([disabled]):not(.is-loading),
button.btn.primary:active:not([disabled]):not(.is-loading) {
  transform: translateY(0) scale(0.97);
  transition: transform var(--dur-press) var(--ease-press) !important;
}

/* Loading buttons — spinner sweeps in beside the label, width preserved
   by the JS helper so the click target doesn't reflow. */
.btn-loading-spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-left: 8px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  vertical-align: -2px;
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 180ms var(--ease-out-soft),
              transform 180ms var(--ease-out-soft);
  animation: btn-spin 0.8s linear infinite;
  animation-play-state: paused;
}
.is-loading .btn-loading-spinner {
  opacity: 1;
  transform: scale(1);
  animation-play-state: running;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
.is-loading { cursor: progress; }

/* Reveal-on-scroll opt-in. Add data-reveal to a section, or
   data-reveal-stagger to a parent for cascading children. The
   IntersectionObserver in app.js handles the .is-revealed flip. */
[data-reveal] {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-reveal) var(--ease-out-soft),
              transform var(--dur-reveal) var(--ease-out-soft);
  will-change: opacity, transform;
}
[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}
[data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-reveal) var(--ease-out-soft),
              transform var(--dur-reveal) var(--ease-out-soft);
}
[data-reveal-stagger].is-revealed > * {
  opacity: 1;
  transform: none;
  transition-delay: calc(var(--reveal-i, 0) * var(--dur-stagger));
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal], [data-reveal].is-revealed,
  [data-reveal-stagger] > *, [data-reveal-stagger].is-revealed > * {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  html.theme-transitioning,
  html.theme-transitioning * {
    transition: none !important;
  }
  .btn-primary:active, .auth-submit:active,
  .hero-cta:active, .pricing-cta:active, .btn-secondary:active {
    transform: none !important;
  }
}

/* Skeleton shimmer for async data placeholders. */
.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--paper-warm);
  border-radius: 8px;
}
.skeleton::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255,255,255,0.55) 50%,
    transparent 100%
  );
  transform: translateX(-100%);
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
[data-theme="dark"] .skeleton::after {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255,255,255,0.06) 50%,
    transparent 100%
  );
}
@keyframes skeleton-shimmer { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) {
  .skeleton::after { animation: none; opacity: 0.5; transform: none; }
}

/* ============================================================
   Navigation skeleton — a full-shell placeholder shown while the
   next page loads. Every page is a full reload (MPA, not an SPA),
   so nav-skeleton.js reveals this over the current page the moment
   a link is followed, and the incoming document tears it down. The
   reveal is delayed a beat in JS so near-instant loads never flash
   it. On app pages the overlay starts past the fixed sidebar so the
   rail stays put; marketing/auth shells use the --full width.
   ============================================================ */
.nav-skel {
  position: fixed;
  inset: 0;
  left: var(--sidebar-w);
  z-index: 40;                 /* under the mobile sidebar drawer (z 50) */
  background: var(--paper);
  padding: 36px 24px;
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 160ms var(--ease-out-soft), visibility 0s linear 160ms;
}
.nav-skel.is-on {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 160ms var(--ease-out-soft);
}
.nav-skel--full { left: 0; }

.nav-skel__inner { max-width: 1080px; margin: 0 auto; }
.nav-skel__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 28px;
}
.nav-skel__title { height: 30px; width: min(240px, 55vw); }
.nav-skel__actions { display: flex; gap: 10px; flex-shrink: 0; }
.nav-skel__pill { height: 34px; width: 92px; border-radius: var(--radius-pill); }
.nav-skel__stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}
.nav-skel__stat,
.nav-skel__panel,
.nav-skel__row {
  border: 1px solid var(--border);   /* mirror the real cards these stand in for */
}
.nav-skel__stat { height: 104px; border-radius: var(--radius-card); }
.nav-skel__panel { height: 260px; border-radius: var(--radius-card); margin-bottom: 24px; }
.nav-skel__rows { display: flex; flex-direction: column; gap: 12px; }
.nav-skel__row { height: 56px; border-radius: var(--radius-md); }

@media (max-width: 768px) {
  .nav-skel { left: 0; padding: 68px 16px 40px; }
  .nav-skel__stats { grid-template-columns: repeat(2, 1fr); }
  .nav-skel__actions .nav-skel__pill:last-child { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .nav-skel { transition: none; }
}

/* Unified toast region — a single stacked widget replaces the five
   inline showToast() copies that used to live in each page-*.js. */
.sc-toast-region {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column-reverse;
  gap: 8px;
  z-index: 9999;
  pointer-events: none;
}
.sc-toast {
  pointer-events: auto;
  position: relative;
  background: var(--ink-deepest);
  color: #fff;
  padding: 10px 16px;
  border-radius: 10px;
  font-size: 13px;
  font-family: var(--font-sans);
  box-shadow: 0 8px 40px rgba(0,0,0,0.20);
  min-width: 180px;
  max-width: min(420px, calc(100vw - 32px));
  opacity: 0;
  transform: translateY(20px) scale(0.96);
  transition: opacity var(--dur-toast-in) var(--ease-out-soft),
              transform var(--dur-toast-in) var(--ease-out-soft);
  overflow: hidden;
}
.sc-toast.is-visible {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.sc-toast.is-leaving {
  opacity: 0;
  transform: translateY(-12px) scale(0.96);
  transition: opacity var(--dur-toast-out) var(--ease-in-sharp),
              transform var(--dur-toast-out) var(--ease-in-sharp);
}
.sc-toast--success { background: var(--green); color: var(--on-green); }
.sc-toast--error   { background: var(--red); }
.sc-toast--info    { background: var(--ink-deepest); border-left: 3px solid var(--green); }
.sc-toast-bar {
  position: absolute;
  left: 0; bottom: 0;
  height: 2px;
  width: 100%;
  background: rgba(255,255,255,0.45);
  transform-origin: left center;
  transform: scaleX(1);
  transition: transform linear;
}
@media (prefers-reduced-motion: reduce) {
  .sc-toast { transition: opacity 80ms linear !important; transform: none !important; }
  .sc-toast.is-visible { transform: none !important; }
  .sc-toast-bar { transition: none !important; }
}

/* Shared modal entry/exit keyframes — page-level modals pick these up
   by toggling .is-open / .is-closing on their overlay container. */
@keyframes sc-overlay-fade-in   { from { opacity: 0; } }
@keyframes sc-overlay-fade-out  { to   { opacity: 0; } }
@keyframes sc-modal-card-in {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
}
@keyframes sc-modal-card-out {
  to   { opacity: 0; transform: translateY(4px) scale(0.98); }
}
@media (prefers-reduced-motion: reduce) {
  @keyframes sc-modal-card-in  { from { opacity: 0; transform: none; } }
  @keyframes sc-modal-card-out { to   { opacity: 0; transform: none; } }
}
