/* ==========================================================================
   Storyfinch design system
   A warm, literary, modern layer on top of Bootstrap 5 — a slick tool for
   authors. Type: Fraunces (display) + Inter (UI). Restrained tokens, layered
   depth, quiet motion.
   ========================================================================== */

:root {
    /* --- Palette -----------------------------------------------------------
       Forest & vellum: a deep navy-black ink and a forest-green accent on warm
       paper, with white card layers, sage dividers, and crimson for alerts.
       Reads as a calm, credible author resource. Every value clears WCAG 2.2 AA
       on the surfaces it is used on; the brief's text-muted was darkened a step
       to reach AA for body text.
       ---------------------------------------------------------------------- */
    --sl-parchment:   #FAF7F2;   /* vellum: main background */
    --sl-parchment-2: #EAEBE4;   /* sage: inactive fills, secondary UI */
    --sl-tile:        #FFFFFF;   /* white card / data-grid layers */
    --sl-ink:         #0D161B;   /* navy-black: headers + body — 17:1 on vellum */
    --sl-ink-soft:    #4A5257;   /* soft charcoal: long descriptions — 7.5:1 */
    --sl-muted:       #63696E;   /* meta/captions — 5.2:1 (brief #737B80 was 4.0, under AA) */
    --sl-line:        #EAEBE4;   /* sage: borders, dividers */
    --sl-line-strong: #808563;   /* form/button borders — 3.6:1 non-text (WCAG 1.4.11) */
    --sl-accent:      #1E3F20;   /* forest: primary buttons, links, accents */
    --sl-accent-dark: #19341F;   /* hover — white text 13.5:1 */
    --sl-accent-deep: #162D1E;   /* pressed */
    --sl-accent-soft: #D7DAD0;   /* pale forest tint: badges, selection — ink 13:1 */

    /* Semantic. Crimson covers warnings + errors (per the brief); success uses
       the forest family since green reads as success and stays on-brand. */
    --sl-success:      #1E3F20;
    --sl-success-soft: #DBDDD5;
    --sl-danger:       #8B2635;  /* crimson: alerts, callouts — 8.1:1 on vellum */
    --sl-danger-dark:  #6C222E;  /* pressed/hover */
    --sl-danger-soft:  #EADAD8;

    /* --- Typography ------------------------------------------------------- */
    /* Display serif (IvyPresto Display) for headlines + branding; grotesque
       (Neue Haas Unica) for body + UI. Both from Adobe Fonts — load via the
       Typekit kit id (config app.fonts.typekit_id). Georgia / system stacks are
       the fallbacks so the site stays intentional before the kit resolves. */
    --sl-display: "ivypresto-display", Georgia, "Times New Roman", serif;
    --sl-serif:   var(--sl-display);   /* alias: existing rules keep working */
    --sl-sans:    "neue-haas-unica", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

    /* Weights */
    --weight-regular: 400; --weight-medium: 500; --weight-semibold: 600; --weight-bold: 700;
    /* Line heights */
    --leading-tight: 1.05;   /* hero headlines — the editorial overlap */
    --leading-snug: 1.25;    /* subheads */
    --leading-normal: 1.55;  /* dashboard body */
    /* Tracking */
    --tracking-tightest: -0.04em;  /* the compressed display look */
    --tracking-tight: -0.01em;
    --tracking-normal: 0em;

    /* Text scale. Five steps, each with one job — everything that is body copy
       or smaller picks from these rather than inventing a size. (Headings use
       the clamp() scale further down; display numerals, the wordmark and icon
       glyphs are deliberate one-offs and sit outside this scale.)
       These replaced an ad-hoc spread of .7/.74/.78/.82/.85/.875/.95rem, which
       is what made type feel unsettled from page to page. */
    --sl-text-2xs:  .75rem;     /* 12px — uppercase micro-labels: eyebrows, badges, column labels */
    --sl-text-xs:   .8125rem;   /* 13px — help text, captions, footnotes */
    --sl-text-sm:   .875rem;    /* 14px — secondary/supporting copy, nav, footer */
    --sl-text-ui:   .9375rem;   /* 15px — buttons, tabs, interactive UI */
    --sl-text-base: 1rem;       /* 16px — body copy */
    --sl-text-lg:   1.125rem;   /* 18px — card titles, ledes, emphasis, small display */

    /* Display scale — ONE set of heading sizes for both marketing and app.
       Every h1-h4 and every display numeral/title pulls from these four steps;
       the app maps its page titles to the smaller steps. Nothing sizes type
       ad-hoc any more (the wordmark logotype is the one deliberate exception). */
    --sl-display-1: clamp(2rem,   2.8vw + .6rem, 3rem);     /* hero        ~48px */
    --sl-display-2: clamp(1.6rem, 2.2vw + .5rem, 2.15rem);  /* section     ~34px */
    --sl-display-3: clamp(1.3rem, 1.4vw + .5rem, 1.6rem);   /* subhead     ~26px */
    --sl-display-4: 1.35rem;                                /* minor/chips  22px */

    /* --- Radius & elevation ---------------------------------------------- */
    --sl-radius-sm: 10px;
    --sl-radius:    16px;
    --sl-radius-lg: 24px;
    --sl-shadow-sm: 0 1px 2px rgba(13, 22, 27, .07);
    --sl-shadow:    0 1px 3px rgba(13, 22, 27, .06), 0 8px 24px -10px rgba(13, 22, 27, .14);
    --sl-shadow-lg: 0 24px 60px -18px rgba(13, 22, 27, .30);

    /* --- Bootstrap overrides --------------------------------------------- */
    --bs-body-bg: var(--sl-parchment);
    --bs-body-color: var(--sl-ink);
    --bs-primary: var(--sl-accent);
    --bs-primary-rgb: 125, 71, 113;   /* must track --sl-accent */
    --bs-border-color: var(--sl-line);
    --bs-body-font-family: var(--sl-sans);
    --bs-body-font-size: 1rem;
    --bs-link-color: var(--sl-accent);
    --bs-link-hover-color: var(--sl-accent-dark);
    --bs-border-radius: var(--sl-radius-sm);
}

* { -webkit-tap-highlight-color: transparent; }

body {
    background-color: var(--sl-parchment);
    /* A whisper of the finch's plum in the paper. */
    background-image:
        radial-gradient(1200px 600px at 100% -5%, rgba(30, 63, 32, .05), transparent 60%),
        radial-gradient(1000px 500px at -10% 0%, rgba(13, 22, 27, .04), transparent 55%);
    background-attachment: fixed;
    color: var(--sl-ink);
    font-family: var(--sl-sans);
    font-size: 1rem;
    line-height: var(--leading-normal);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

::selection { background: var(--sl-accent-soft); color: var(--sl-accent-dark); }

/* --- Skip link (WCAG 2.4.1 Bypass Blocks) --------------------------------- */
/* Hidden off-screen until keyboard-focused, then it's the first stop on the
   page so keyboard/AT users can jump past the nav straight to content. */
/* Honeypot: off-screen rather than display:none, since some bots skip fields
   that are not rendered. aria-hidden + tabindex="-1" keep it out of reach of
   anyone actually using the form. */
.sl-hp {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.sl-skip-link {
    position: absolute;
    top: -3rem;
    left: 1rem;
    z-index: 2000;
    background: var(--sl-accent-dark);
    color: #fff;
    padding: .6rem 1.1rem;
    border-radius: var(--sl-radius-sm);
    text-decoration: none;
    font-weight: 600;
    transition: top .15s ease;
}
.sl-skip-link:focus {
    top: 1rem;
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* --- Typography ---------------------------------------------------------- */
h1, h2, h3, h4, h5, h6, .sl-serif, .navbar-brand {
    font-family: var(--sl-display);
    color: var(--sl-ink);
}
/* Editorial display hierarchy (marketing hero scale). Fluid clamp so headlines
   scale from mobile to desktop; the app steps these down below. */
h1, .h1 { font-weight: var(--weight-bold);     line-height: var(--leading-tight); letter-spacing: var(--tracking-tightest); font-size: var(--sl-display-1); text-wrap: balance; }
h2, .h2 { font-weight: var(--weight-semibold); line-height: var(--leading-snug);  letter-spacing: var(--tracking-tightest); font-size: var(--sl-display-2); }
h3, .h3 { font-weight: var(--weight-medium);   line-height: var(--leading-snug);  letter-spacing: -0.02em;                   font-size: var(--sl-display-3); }
h4, .h4 { font-weight: var(--weight-semibold); line-height: var(--leading-snug);  letter-spacing: var(--tracking-tight);     font-size: var(--sl-display-4); }
h5, .h5, h6, .h6 { font-weight: var(--weight-semibold); line-height: var(--leading-snug); letter-spacing: var(--tracking-tight); }
/* Inside the authored app, headings step down a size. The scale above is tuned
   for marketing pages, where an h1 is a hero; a dashboard page title set at
   hero size reads as shouting, and made app pages feel unrelated to each other.
   Scoped to .sl-main so marketing (which uses the bare <main>) is untouched. */
.sl-main h1 { font-weight: var(--weight-semibold); font-size: var(--sl-display-2);  line-height: var(--leading-snug); letter-spacing: -0.02em; }
.sl-main h2 { font-size: var(--sl-display-3);  letter-spacing: -0.02em; }
.sl-main h3 { font-size: var(--sl-display-4);  letter-spacing: var(--tracking-tight); }
/* Card/list-item titles: serif, sized off the scale rather than an ad-hoc
   .fs-5, so every card across the app matches. */
.sl-card-title {
    font-family: var(--sl-serif);
    font-optical-sizing: auto;
    font-size: var(--sl-text-lg);
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.015em;
    color: var(--sl-ink);
}
p  { color: var(--sl-ink); }

/* --- Text colour roles ---------------------------------------------------- */
/* Four roles, and nothing else should set a text colour directly:
     --sl-ink       primary copy and headings
     --sl-ink-soft  secondary copy (ledes, longer supporting prose)
     --sl-muted     tertiary: labels, captions, metadata            -> .text-muted-2
     --sl-danger / --sl-success  state, never decoration
   Bootstrap's .text-danger/.text-success were previously falling through to
   its own palette (#dc3545 / #198754). Those are cold next to the warm ink
   here, and — because they are used for form error messages — they only reach
   4.2:1 on parchment, under the 4.5:1 WCAG AA minimum for body text. The
   palette equivalents below clear it (5.29:1 and 4.76:1). */
.text-muted-2 { color: var(--sl-muted) !important; }
.text-danger  { color: var(--sl-danger) !important; }
.text-success { color: var(--sl-success) !important; }

/* --- Weight scale --------------------------------------------------------- */
/* Three weights, no more:
     400  body copy
     500  buttons, nav links — UI that should sit back
     600  headings, labels, emphasis
   <strong> and <th> default to 700 in the browser, which rendered emphasis
   *heavier* than our own headings. Pinning them to 600 settles that, and with
   nothing left asking for 700 the Inter 700 cut is no longer requested. */
strong, b, th { font-weight: 600; }
.sl-lead {
    /* Lede paragraph — body sans, just larger. The serif is reserved for
       headings, so a lede reads as emphasised body copy, not a headline. */
    font-family: var(--sl-sans);
    font-size: var(--sl-text-lg);
    font-weight: var(--weight-regular);
    line-height: var(--leading-normal);
    color: var(--sl-ink-soft);
}
.small, small { font-size: var(--sl-text-sm); }

a {
    color: var(--sl-accent);
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
    transition: color .12s ease;
}
a:hover { color: var(--sl-accent-dark); }

/* --- Brand wordmark ------------------------------------------------------ */
.sl-wordmark {
    font-family: var(--sl-serif);
    font-weight: 600;
    font-size: 1.85rem;
    letter-spacing: -0.02em;
    color: var(--sl-ink);
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    text-decoration: none;
}
.sl-wordmark:hover { color: var(--sl-ink); }

.sl-card-heading {
    font-family: var(--sl-sans);
    font-weight: var(--weight-semibold);
    font-size: var(--sl-text-lg);
    line-height: var(--leading-snug);
    letter-spacing: var(--tracking-tight);
    color: var(--sl-ink);
}
/* --- Buttons ------------------------------------------------------------- */
.btn {
    --bs-btn-border-radius: 11px;
    border-radius: 11px;
    font-family: var(--sl-sans);
    font-weight: var(--weight-semibold);
    font-size: var(--sl-text-ui);
    letter-spacing: var(--tracking-tight);
    padding: .55rem 1.1rem;
    transition: transform .12s ease, box-shadow .12s ease, background-color .12s ease, color .12s ease, border-color .12s ease;
}
.btn:active { transform: translateY(1px); }
.btn-primary {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--sl-accent);
    --bs-btn-border-color: var(--sl-accent);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--sl-accent-dark);
    --bs-btn-hover-border-color: var(--sl-accent-dark);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--sl-accent-deep);
    --bs-btn-active-border-color: var(--sl-accent-deep);
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--sl-accent);
    --bs-btn-disabled-border-color: var(--sl-accent);
}
.btn-primary:hover { transform: translateY(-1px); }
/* Reader-facing pages are branded with the author's own colours, so the plum
   hover above (a Storyfinch accent) must not apply there: a crimson button
   turning purple on hover is not their brand. Derive the hover and pressed
   states from whatever colour the page is actually using. */
/* --sl-accent-soft is a designed value in the app and on marketing (it matches
   the homepage illustration), but on a branded reader page it left a teal text
   selection on, say, a crimson page. Derive it from whatever accent the page is
   actually using. Mixing into --sl-tile rather than white means it follows the
   landing theme too, staying dark on the dark theme. */
.sl-landing {
    --sl-accent-soft: color-mix(in srgb, var(--sl-accent) 14%, var(--sl-tile));
}
.sl-landing .btn-primary {
    /* Each of these falls back to the accent, so a magnet that only sets an
       accent colour renders exactly as it did before these fields existed.
       They are set inline by landing_colour_style(). */
    --bs-btn-bg: var(--sl-btn-bg, var(--sl-accent));
    --bs-btn-border-color: var(--sl-btn-bg, var(--sl-accent));
    --bs-btn-hover-bg: var(--sl-btn-bg-dark, var(--sl-accent-dark));
    --bs-btn-hover-border-color: var(--sl-btn-bg-dark, var(--sl-accent-dark));
    --bs-btn-active-bg: var(--sl-btn-bg-dark, var(--sl-accent-dark));
    --bs-btn-active-border-color: var(--sl-btn-bg-dark, var(--sl-accent-dark));
    /* Button text was hard white, which an author could not fix on a light
       brand colour. */
    --bs-btn-color: var(--sl-btn-ink, #fff);
    --bs-btn-hover-color: var(--sl-btn-ink, #fff);
    --bs-btn-active-color: var(--sl-btn-ink, #fff);
}
.btn-outline-primary {
    --bs-btn-color: var(--sl-accent-dark);
    --bs-btn-border-color: var(--sl-line-strong);
    --bs-btn-hover-bg: var(--sl-accent-dark);
    --bs-btn-hover-border-color: var(--sl-accent-dark);
    --bs-btn-hover-color: #fff;
    --bs-btn-active-bg: var(--sl-accent-deep);
    background: transparent;
}
.btn-outline-secondary {
    --bs-btn-color: var(--sl-ink-soft);
    --bs-btn-border-color: var(--sl-line-strong);
    --bs-btn-hover-bg: var(--sl-parchment-2);
    --bs-btn-hover-border-color: var(--sl-line-strong);
    --bs-btn-hover-color: var(--sl-ink);
    background: transparent;
}
.btn-danger {
    --bs-btn-bg: var(--sl-danger);
    --bs-btn-border-color: var(--sl-danger);
    --bs-btn-hover-bg: var(--sl-danger-dark);
    --bs-btn-hover-border-color: var(--sl-danger-dark);
    --bs-btn-active-bg: var(--sl-danger-dark);
    --bs-btn-disabled-bg: var(--sl-danger);
    --bs-btn-disabled-border-color: var(--sl-danger);
}
.btn-lg { padding: .8rem 1.6rem; font-size: var(--sl-text-base); border-radius: 13px; }
.btn-sm { padding: .35rem .75rem; border-radius: 9px; }

/* --- Segmented control (radio .btn-group) -------------------------------- */
/* Bootstrap renders .btn-group + .btn-check as a row of outline buttons and
   falls back to its own grey for the checked segment, which is off-palette
   here. Restyle as a segmented control: a recessed parchment track with a
   raised tile marking the selection. :has() scopes this to radio groups, so
   a plain .btn-group row of ordinary buttons is left alone. */
.btn-group:has(> .btn-check) {
    background: var(--sl-parchment-2);
    border: 1px solid var(--sl-line);
    border-radius: 11px;
    padding: 3px;
    gap: 2px;
}
.btn-group > .btn-check + .btn {
    margin-left: 0;
    border: 0;
    /* Bootstrap squares the inner corners of grouped buttons at a higher
       specificity than we can reach cleanly; each segment is its own pill. */
    border-radius: 8px !important;
    background: transparent;
    color: var(--sl-muted);
    font-weight: 600;
    box-shadow: none;
    transition: background-color .12s ease, color .12s ease;
}
.btn-group > .btn-check + .btn:hover { background: transparent; color: var(--sl-ink); }
.btn-group > .btn-check:checked + .btn {
    background: var(--sl-tile);
    color: var(--sl-accent-dark);
}
/* Explicit focus ring: Bootstrap hides the radio itself, so without this the
   only focus cue comes from CDN defaults we don't control (WCAG 2.4.7). */
.btn-group > .btn-check:focus-visible + .btn {
    outline: 2px solid var(--sl-accent);
    outline-offset: -2px;
}
.btn-group > .btn-check:disabled + .btn { color: var(--sl-muted); opacity: .65; cursor: default; }
.btn-group > .btn-check:disabled:checked + .btn { background: var(--sl-tile); box-shadow: none; }

/* Danger zone: no red fill. A soft red border, compact padding, red heading. */
.sl-danger-zone { border: 1px solid var(--sl-danger-soft); }
.sl-panel.sl-danger-zone { padding: 1.5rem 1.75rem; }
.sl-danger-zone h2 { color: var(--sl-danger); }

/* --- Cards & surfaces ---------------------------------------------------- */
.sl-card, .card {
    background: var(--sl-tile);
    border: 1px solid var(--sl-line);
    border-radius: var(--sl-radius);
    box-shadow: var(--sl-shadow);
    transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
a.sl-card { text-decoration: none; color: inherit; display: block; }
a.sl-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 18px 44px -20px rgba(13, 22, 27, .3);
    border-color: var(--sl-line-strong);
}
.sl-panel {
    background: var(--sl-tile);
    border: 1px solid var(--sl-line);
    border-radius: var(--sl-radius);
    box-shadow: var(--sl-shadow-sm);
    padding: 2.25rem;
}
@media (min-width: 768px) { .sl-panel { padding: 2.5rem; } }
.sl-stat {
    position: relative;
    background: var(--sl-tile);
    border: 1px solid var(--sl-line);
    border-radius: var(--sl-radius);
    box-shadow: var(--sl-shadow-sm);
    padding: 1.5rem 1.6rem;
    overflow: hidden;
}
.sl-stat-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.25rem; height: 2.25rem;
    margin-bottom: .9rem;
    border-radius: 10px;
    background: var(--sl-accent-soft);
    color: var(--sl-accent-dark);
    font-size: var(--sl-text-lg);
}
.sl-stat .sl-stat-value {
    font-family: var(--sl-serif);
    font-optical-sizing: auto;
    font-size: var(--sl-display-2);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--sl-ink);
}
.sl-stat .sl-stat-label {
    color: var(--sl-muted);
    font-size: var(--sl-text-2xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .09em;
    margin-top: .35rem;
}

/* --- Forms --------------------------------------------------------------- */
.form-control, .form-select {
    border-radius: var(--sl-radius-sm);
    border: 1.5px solid var(--sl-line-strong);
    background-color: transparent;
    color: var(--sl-ink);
    padding: .7rem .95rem;
    transition: border-color .12s ease, box-shadow .12s ease;
}
.form-control::placeholder { color: var(--sl-muted); } /* was #B7AE9F (~2:1); --sl-muted clears 4.5:1 (WCAG 1.4.3) */
.form-control:hover, .form-select:hover { border-color: var(--sl-muted); }
.form-control:focus, .form-select:focus {
    border-color: var(--sl-accent);
    box-shadow: 0 0 0 .22rem color-mix(in srgb, var(--sl-accent) 16%, transparent);
}
.form-label { font-weight: 600; color: var(--sl-ink); margin-bottom: .4rem; }
.form-text { color: var(--sl-muted); font-size: var(--sl-text-xs); }
.form-check-input { border-color: var(--sl-line-strong); }
.form-check-input:checked { background-color: var(--sl-accent); border-color: var(--sl-accent); }
.form-check-input:focus { border-color: var(--sl-accent); box-shadow: 0 0 0 .22rem color-mix(in srgb, var(--sl-accent) 16%, transparent); }
.input-group-text { background: var(--sl-parchment-2); border: 1.5px solid var(--sl-line-strong); color: var(--sl-muted); border-radius: var(--sl-radius-sm); }

/* --- Badges & pills ------------------------------------------------------ */
.sl-badge {
    display: inline-flex; align-items: center; gap: .3em;
    font-size: var(--sl-text-2xs); font-weight: 600; line-height: 1;
    padding: .4em .7em; border-radius: 999px;
    letter-spacing: .01em;
}
.sl-badge-active   { background: var(--sl-accent-soft); color: var(--sl-accent-dark); }
.sl-badge-inactive { background: var(--sl-parchment-2); color: var(--sl-muted); }
.sl-badge-pro      { background: var(--sl-accent-soft); color: var(--sl-accent-dark); }

/* --- Form tabs (reader magnet editor) ------------------------------------ */
/* The active tab joins the pane below it: the nav's bottom border forms the
   pane's top edge, and the active tab masks it with the tile colour. */
.sl-form-tabs {
    border-bottom: 1px solid var(--sl-line);
    gap: .25rem;
    flex-wrap: wrap;
    margin-bottom: 0 !important;
}
.sl-form-tabs .nav-link {
    border: 1px solid transparent;
    border-bottom: 0;
    border-radius: var(--sl-radius-sm) var(--sl-radius-sm) 0 0;
    color: var(--sl-muted);
    font-weight: 600;
    padding: .7rem 1.1rem;
    margin-bottom: -1px;
}
.sl-form-tabs .nav-link:hover { color: var(--sl-ink); background: var(--sl-parchment-2); }
.sl-form-tabs .nav-link.active {
    color: var(--sl-accent-dark);
    background: var(--sl-tile);
    border-color: var(--sl-line);
    border-bottom: 1px solid var(--sl-tile);
}
.sl-form-tabs + .tab-content {
    background: var(--sl-tile);
    border: 1px solid var(--sl-line);
    border-top: 0;
    border-radius: 0 0 var(--sl-radius) var(--sl-radius);
    box-shadow: var(--sl-shadow-sm);
    padding: 2.25rem;
}
@media (min-width: 768px) { .sl-form-tabs + .tab-content { padding: 2.5rem; } }
/* Give each field room to breathe: the signup tab in particular packs a lot
   of radios and textareas together. */
.sl-form-tabs + .tab-content .mb-3 { margin-bottom: 1.75rem !important; }
.sl-form-tabs + .tab-content .mb-2 { margin-bottom: 1.25rem !important; }
.sl-form-tabs + .tab-content .form-check { margin-bottom: .6rem; }
.sl-form-tabs + .tab-content .form-check:last-child { margin-bottom: 0; }
.sl-form-tabs + .tab-content .form-text { margin-top: .4rem; }
.sl-form-tabs + .tab-content > div > div:last-child { margin-bottom: 0 !important; }
/* A label that introduces a group of radios needs a touch more separation. */
.sl-form-tabs + .tab-content .form-label.d-block { margin-bottom: .7rem; }

/* --- Plan / pricing cards ------------------------------------------------ */
.sl-plan-featured { border-color: var(--sl-accent); }
.sl-plan-price {
    font-family: var(--sl-serif);
    font-size: var(--sl-display-2); font-weight: 600; letter-spacing: -.02em;
}
.sl-plan-features { list-style: none; padding-left: 0; }
.sl-plan-features li {
    display: flex; align-items: flex-start; gap: .5rem; margin-bottom: .5rem;
}
.sl-plan-features li::before {
    content: "✦"; color: var(--sl-accent); flex: 0 0 auto;
}

/* --- App main content rhythm --------------------------------------------- */
/* Generous vertical breathing room so pages never feel cramped. */
.sl-main { padding-top: .5rem; }
.sl-main > .sl-panel,
.sl-main > .sl-card,
.sl-main > .row,
.sl-main > section { margin-bottom: 2rem; }
.sl-main > section:last-child,
.sl-main > .row:last-child { margin-bottom: 0; }
.sl-section-head { margin-bottom: 1.75rem; }

/* --- Navbar (author app) ------------------------------------------------- */
.sl-navbar {
    position: sticky; top: 0; z-index: 1030;
    background: rgba(250, 247, 242, .82);   /* --sl-parchment (vellum) at 82% */
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--sl-line);
}
.sl-navbar .nav-link {
    color: var(--sl-ink-soft); font-weight: 500; font-size: var(--sl-text-sm);
    border-radius: 9px; padding: .42rem .8rem;
    transition: color .12s ease, background-color .12s ease;
}
.sl-navbar .nav-link:hover { color: var(--sl-accent-dark); background: var(--sl-accent-soft); }
.sl-navbar .nav-link.active { color: var(--sl-accent-dark); background: var(--sl-accent-soft); font-weight: var(--weight-semibold); }

/* Dropdown menus: beige, not white. */
.dropdown-menu {
    --bs-dropdown-bg: var(--sl-parchment);
    --bs-dropdown-border-color: var(--sl-line);
    --bs-dropdown-link-color: var(--sl-ink-soft);
    --bs-dropdown-link-hover-bg: var(--sl-parchment-2);
    --bs-dropdown-link-hover-color: var(--sl-ink);
    --bs-dropdown-link-active-bg: var(--sl-accent-soft);
    --bs-dropdown-link-active-color: var(--sl-accent-dark);
}

/* --- Tables -------------------------------------------------------------- */
/* --bs-table-color, not just `color`: Bootstrap 5.3 paints cells via
   `.table > :not(caption) > * > *`, which outranks a plain `color` here and
   resolves to --bs-emphasis-color (pure #000). Every table in the app was
   therefore rendering black text beside warm --sl-ink prose. */
.table { --bs-table-bg: transparent; --bs-table-color: var(--sl-ink); color: var(--sl-ink); margin-bottom: 0; }
.table > :not(caption) > * > * { padding-top: .85rem; padding-bottom: .85rem; }
.table > thead th { border-bottom: 1px solid var(--sl-line); font-weight: 600; }
.table > tbody > tr { border-color: var(--sl-line); }
.table > tbody > tr:last-child > * { border-bottom: 0; }
.table-hover > tbody > tr:hover > * { background: var(--sl-parchment-2); }
/* Bootstrap's .table-responsive sets overflow-x: auto but never overflow-y —
   per the CSS overflow spec, setting overflow-x to anything but "visible"
   forces the browser to compute overflow-y as "auto" too (you cannot mix
   "visible" on one axis with a non-visible value on the other). That silently
   makes every one of these a two-axis scroll container, so the smallest
   sub-pixel rounding in a table's rendered height raises a vertical scrollbar
   nobody asked for. Declaring overflow-y: hidden is a valid pairing and rules
   it out; these wrappers only ever need to scroll sideways. */
.table-responsive { overflow-y: hidden; }

/* --- Responsive stacked tables ------------------------------------------- */
/* Below lg, a data table stops being a table visually and becomes a stack of
   cards: one block per row, each cell on its own line with its column heading
   as a small label. This replaces horizontal scrolling, which hides data off
   the side of the screen and is easy to miss entirely on touch.
   The markup stays a real <table> throughout — only `display` changes — so
   table semantics (and the <caption>/scope headers) still reach assistive
   tech. Labels come from a data-label attribute on each <td>. */
@media (max-width: 991.98px) {
    .sl-table-stack thead { display: none; }
    .sl-table-stack,
    .sl-table-stack tbody,
    .sl-table-stack tr,
    .sl-table-stack td { display: block; width: 100%; }
    .sl-table-stack tbody tr {
        padding: 1rem;
        border-bottom: 1px solid var(--sl-line);
    }
    .sl-table-stack tbody tr:last-child { border-bottom: 0; }
    .sl-table-stack td { border: 0; padding: .3rem 0; text-align: left; }
    /* The first cell is the row's identity (title, email, connection name), so
       it leads the card rather than carrying a label. */
    .sl-table-stack td:first-child { padding-top: 0; padding-bottom: .5rem; }
    .sl-table-stack td[data-label] {
        display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    }
    .sl-table-stack td[data-label]::before {
        content: attr(data-label);
        flex: 0 0 auto;
        font-size: var(--sl-text-2xs); font-weight: 600;
        text-transform: uppercase; letter-spacing: .06em;
        color: var(--sl-ink);
    }
    /* Row actions sit full-width at the foot of the card, comfortably tappable. */
    .sl-table-stack td.sl-stack-action { padding-top: .85rem; }
    .sl-table-stack td.sl-stack-action .btn { width: 100%; }
}

/* Feature-comparison table (marketing homepage "Why Storyfinch" section). */
.sl-compare thead th {
    background: var(--sl-ink);
    color: #fff;
    font-size: var(--sl-text-2xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .07em;
    padding-top: 1.1rem;
    padding-bottom: 1.1rem;
}

/* Fixed layout + explicit column widths: the table is always exactly 100% of
   its container, so cell content wraps instead of ever being able to force
   the table (and therefore the page) wider — this is what actually
   guarantees no horizontal scroll, regardless of font metrics or browser,
   rather than relying on the content happening to fit. */
@media (min-width: 992px) {
    .sl-compare { table-layout: fixed; }
    .sl-compare th:first-child, .sl-compare td:first-child { width: 34%; }
    .sl-compare th:not(:first-child), .sl-compare td:not(:first-child) { width: 22%; }
    .sl-compare td, .sl-compare th { overflow-wrap: break-word; }
}
.sl-compare td.sl-compare-highlight { color: var(--sl-accent-dark); }
.sl-compare-yes { color: var(--sl-accent); font-size: var(--sl-text-lg); }
.sl-compare-no  { color: var(--sl-muted); font-size: var(--sl-text-lg); }
/* Stacking below lg comes from .sl-table-stack; these are the comparison
   table's own additions on top of it. */
@media (max-width: 991.98px) {
    .sl-compare td:first-child {
        font-family: var(--sl-serif);
        font-size: var(--sl-text-lg);
        font-weight: 600;
    }
    .sl-compare td.sl-compare-highlight::before { color: var(--sl-accent-dark); }
}

/* --- Alerts -------------------------------------------------------------- */
.alert { border-radius: var(--sl-radius-sm); border: 1px solid transparent; }
.alert-success { background: var(--sl-success-soft); color: var(--sl-success); border-color: color-mix(in srgb, var(--sl-success) 26%, transparent); }
.alert-warning { background: var(--sl-accent-soft); color: var(--sl-accent-deep); border-color: color-mix(in srgb, var(--sl-accent) 24%, transparent); }
.alert-danger  { background: var(--sl-danger-soft); color: var(--sl-danger); border-color: rgba(168,64,44,.2); }

/* --- Auth / public shells ------------------------------------------------ */
.sl-auth-shell {
    min-height: 100vh; display: flex; align-items: center;
    padding: 2rem 0;
}
.sl-auth-card { max-width: 430px; width: 100%; margin: 0 auto; }
.sl-auth-card .sl-card { box-shadow: var(--sl-shadow-lg); }

/* --- Public reader magnet landing --------------------------------------- */
.sl-landing { min-height: 100vh; }
.sl-landing-cover {
    border-radius: 14px;
    box-shadow: var(--sl-shadow-lg);
    max-width: 100%;
    height: auto;
    transform: rotate(-1.2deg);
    transition: transform .25s ease;
}
.sl-landing-cover:hover { transform: rotate(0deg) translateY(-2px); }
.sl-cover-fallback {
    aspect-ratio: 2 / 3;
    background: linear-gradient(155deg, var(--sl-accent) 0%, var(--sl-accent-dark) 100%);
    color: #fff;
    border-radius: 14px;
    display: flex; align-items: center; justify-content: center;
    padding: 2rem; text-align: center;
    font-family: var(--sl-serif); font-weight: 500; font-size: var(--sl-display-4);
    line-height: 1.3;
    box-shadow: var(--sl-shadow-lg);
}

/* --- Support tickets ------------------------------------------------------ */
/* Rows in the ticket list. The whole row is one link with a status pill beside
   it, rather than a link nested inside a link, so keyboard order stays sane. */
.sl-ticket-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .9rem 1.15rem;
    border-bottom: 1px solid var(--sl-line);
}
.sl-ticket-row:last-child { border-bottom: 0; }
.sl-ticket-link {
    display: block;
    min-width: 0;                 /* lets the subject truncate instead of pushing the pill off */
    text-decoration: none;
    color: inherit;
    flex: 1 1 auto;
}
.sl-ticket-link:hover .sl-ticket-subject { text-decoration: underline; }
.sl-ticket-subject {
    display: block;
    font-weight: 600;
    color: var(--sl-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.sl-ticket-meta {
    display: block;
    margin-top: .15rem;
    font-size: var(--sl-text-xs);
    color: var(--sl-muted);
}

/* Status filter for the ticket queue. Styled here rather than leaning on
   Bootstrap's .nav-pills, whose active background resolves through variables
   the design system overrides, so the selected filter read as plain text. */
.sl-filter-nav { display: flex; flex-wrap: wrap; gap: .5rem; list-style: none; padding: 0; margin: 0; }
.sl-filter-nav a {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    min-height: 44px;              /* comfortably past the 24px target minimum (WCAG 2.5.8) */
    padding: .4rem .9rem;
    border-radius: 999px;
    border: 1px solid var(--sl-line);
    background: var(--sl-tile);
    color: var(--sl-ink-soft);
    font-size: var(--sl-text-sm);
    font-weight: 500;
    text-decoration: none;
}
.sl-filter-nav a:hover { border-color: var(--sl-line-strong); color: var(--sl-ink); }
.sl-filter-nav a[aria-current="page"] {
    background: var(--sl-accent-soft);
    border-color: var(--sl-accent-soft);
    color: var(--sl-accent-dark);   /* 9:1 on accent-soft */
    font-weight: 600;
}
.sl-filter-nav .sl-filter-count { color: inherit; opacity: .75; font-weight: 400; }

/* The conversation. Staff and author messages sit on opposite tints so a long
   thread is scannable, but both stay full width: these are letters, not chat. */
.sl-thread { display: flex; flex-direction: column; gap: 1rem; }
.sl-thread-item {
    border: 1px solid var(--sl-line);
    border-left: 3px solid var(--sl-line-strong);
    border-radius: var(--sl-radius-sm);
    padding: .85rem 1rem;
    background: var(--sl-parchment);
}
.sl-thread-mine {
    border-left-color: var(--sl-accent);
    background: var(--sl-tile);
}
.sl-thread-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    margin-bottom: .4rem;
    font-size: var(--sl-text-xs);
    color: var(--sl-muted);
}
.sl-thread-who { font-weight: 600; color: var(--sl-ink-soft); }
/* Bodies are plain text typed by a person: escaped on output, then wrapped
   here so their line breaks survive without any markup being interpreted. */
.sl-thread-body {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-size: var(--sl-text-base);
}

/* --- Landing themes ------------------------------------------------------ */
/* Light (default) — the cream paper. */
.sl-landing.sl-theme-light { background: var(--sl-parchment-2); }

/* Dark. Redefines the palette tokens rather than restyling components one by
   one: cards, labels, help text, footer and muted copy already paint from
   these, so the theme is three text roles here instead of the seven ad-hoc
   greys it had grown (#ece7dd/#f4efe6/#f7f2e9/#cfc7b9/#b7af9f/#968d7d/#8a8272,
   several of them duplicating tokens the theme was already setting).
   Ratios below are against the card (#24221D), the tightest of the three
   surfaces; all clear 4.5:1. */
.sl-landing.sl-theme-dark {
    --sl-parchment:   #1A1916;
    --sl-parchment-2: #24221D;
    --sl-tile:        #24221D;
    --sl-ink:         #F4EFE6;   /* 13.9:1 */
    --sl-ink-soft:    #CFC7B9;   /*  9.5:1 */
    --sl-muted:       #A79D8C;   /*  5.9:1 */
    --sl-line:        #35312B;
    --sl-line-strong: #786F60;   /*  3.2:1 for non-text contrast (WCAG 1.4.11); was #6F6759 at 2.85:1 */
    /* The brand forest reaches only ~1.3:1 on this ground, so links take a
       lightened tint of it. An author-chosen accent is written inline onto this
       element by go/landing.php and deliberately still wins over these: picking
       a dark accent alongside the dark theme is the author's call, and their
       branding is not overridden for them. Do not "fix" that by forcing a
       colour here — it would silently discard their choice. */
    --bs-link-color:       #629964;   /* 4.7:1 */
    --bs-link-hover-color: #8EB790;   /* 7.0:1 */
    background: var(--sl-parchment);
    color: var(--sl-ink);
}
/* Fields sit a shade below the card so they still read as inputs. */
.sl-landing.sl-theme-dark .form-control { background: #1F1D19; }
/* Links resolve from --bs-link-color rather than --sl-accent, because the base
   `a` rule paints straight from --sl-accent and would otherwise ignore the
   lightened value above. Reading it from --bs-link-color also means an
   author-supplied accent (written inline by go/landing.php, which sets both
   --sl-accent and --bs-link-color) still takes precedence over our default. */
.sl-landing.sl-theme-dark a { color: var(--bs-link-color); }
.sl-landing.sl-theme-dark a:hover { color: var(--bs-link-hover-color); }
/* Footer links stay the quiet ink-soft they are in the light theme (9.5:1). */
.sl-landing.sl-theme-dark .sl-footer a { color: var(--sl-ink-soft); }
/* The wordmark is branding, not a link: it should read as ink on every theme.
   It needs restating here because the rule above outranks .sl-wordmark's own
   colour, which would otherwise tint the brand name with the link accent. */
.sl-landing.sl-theme-dark .sl-wordmark,
.sl-landing.sl-theme-dark .sl-wordmark:hover { color: var(--sl-ink); }
/* Brick red falls to 3.09:1 here, so error text takes a lighter tint. Scoped to
   .text-danger rather than the --sl-danger token, which also fills buttons. */
.sl-landing.sl-theme-dark .text-danger { color: #E38A72 !important; }   /* 6.2:1 */

/* Classic — traditional cream, serif-forward, quiet bordered card. */
.sl-landing.sl-theme-classic { background: #f4ecd7; }
.sl-landing.sl-theme-classic .sl-card { border: 1px solid var(--sl-line-strong); box-shadow: none; border-radius: 6px; }
.sl-landing.sl-theme-classic h1 { font-size: var(--sl-display-1); }
.sl-landing.sl-theme-classic .sl-landing-cover { border-radius: 4px; }

/* Minimal — pure white, thin borders, airy. */
.sl-landing.sl-theme-minimal { background: #ffffff; }
.sl-landing.sl-theme-minimal .sl-card { background: #ffffff; box-shadow: none; border: 1px solid var(--sl-line); border-radius: 10px; }
.sl-landing.sl-theme-minimal .sl-landing-cover { transform: none; box-shadow: 0 8px 30px -14px rgba(0, 0, 0, .22); }
.sl-landing.sl-theme-minimal .sl-cover-fallback { box-shadow: none; }

/* --- Legal / policy pages ------------------------------------------------ */
/* --- Blog article body ---------------------------------------------------- */
/* An inset rule above each section heading, with generous space around it. */
.sl-article h2::before {
    content: "";
    display: block;
    border-top: 1px solid var(--sl-line);
    margin: 3rem 0 2.25rem;
}
.sl-article h2:first-of-type::before { display: none; }
.sl-article h2:first-of-type { margin-top: 2rem; }
.sl-article h3 { margin-top: 2rem; }
.sl-article p, .sl-article ul, .sl-article ol { margin-bottom: 1.15rem; }
.sl-article li { margin-bottom: .4rem; }
@media (max-width: 575.98px) {
    .sl-article h2::before { margin: 2.25rem 0 1.75rem; }
}

/* FAQ accordion (native <details>, no JS). */
.sl-faq {
    border: 1px solid var(--sl-line);
    border-radius: var(--sl-radius-sm);
    background: var(--sl-tile);
    margin-bottom: .6rem;
}
.sl-faq > summary {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    padding: .95rem 1.15rem;
    font-family: var(--sl-sans);
    font-weight: var(--weight-semibold);
    font-size: var(--sl-text-lg);
    letter-spacing: var(--tracking-tight);
    cursor: pointer;
    list-style: none;
    transition: color .12s ease;
}
.sl-faq > summary::-webkit-details-marker { display: none; }
.sl-faq > summary::after {
    content: "+";
    flex: 0 0 auto;
    font-size: var(--sl-display-4); line-height: 1;
    color: var(--sl-accent);
    transition: transform .18s ease;
}
.sl-faq[open] > summary::after { content: "−"; }
.sl-faq > summary:hover { color: var(--sl-accent-dark); }
.sl-faq > summary:focus-visible {
    outline: 2px solid var(--sl-accent);
    outline-offset: -2px;
    border-radius: var(--sl-radius-sm);
}
.sl-faq-body { padding: 0 1.15rem .35rem; }
.sl-faq-body > *:last-child { margin-bottom: .75rem; }

.sl-legal { color: var(--sl-ink); }
.sl-legal .sl-lede { font-size: var(--sl-text-lg); color: var(--sl-ink-soft); }
.sl-legal h2 { margin: 2.75rem 0 1rem; }
.sl-legal h2:first-of-type { margin-top: 2rem; }
.sl-legal h3 { margin: 1.5rem 0 .5rem; }
.sl-legal p, .sl-legal ul, .sl-legal ol { margin-bottom: 1rem; line-height: 1.7; }
.sl-legal ul, .sl-legal ol { padding-left: 1.25rem; }
.sl-legal li { margin-bottom: .35rem; }
.sl-legal .sl-address { color: var(--sl-ink-soft); }

/* Framed product screenshot. */
.sl-shot { border: 1px solid var(--sl-line-strong); border-radius: 14px; overflow: hidden; box-shadow: var(--sl-shadow); background: #fff; }
.sl-shot img { display: block; width: 100%; height: auto; }


/* Contextual help rail beside the tabbed pages. Sticks below the navbar so it
   stays with you down a long form; the offset clears the sticky .sl-navbar. */
@media (min-width: 992px) {
    .sl-help-rail { position: sticky; top: 5.5rem; }
}
.sl-help-rail h2 { font-size: var(--sl-text-lg); }

/* --- Colour swatch fields (reader-magnet Design tab) ---------------------- */
/* A colour input always renders *some* colour, so on its own it cannot show
   whether the author set that value or is inheriting it. The swatch is drawn
   solid when set and dashed-and-faded when following something else, with the
   state also spelled out in words beside it. */
.sl-swatch-chip {
    width: 44px; height: 38px; padding: 2px;
    border-radius: 9px;
    border: 1.5px solid var(--sl-line-strong);
    background: none;
}
.sl-swatch:not(.is-set) .sl-swatch-chip {
    border-style: dashed;
    opacity: .55;
}
.sl-swatch-state {
    font-size: var(--sl-text-xs);
    color: var(--sl-muted);
}
.sl-swatch.is-set .sl-swatch-state { color: var(--sl-accent-dark); font-weight: 600; }
/* The clear control only makes sense once there is something to clear. */
.sl-swatch:not(.is-set) .sl-swatch-clear { display: none; }

/* --- Utility ------------------------------------------------------------- */
/* Caps a block at the col-lg-9 equivalent (75%). Page descriptions that ran the
   full width of a wide window were hard to read — the line got far longer than
   a comfortable measure — and left pages looking unstructured. Below lg the
   container is already narrow enough, so the cap lifts rather than squeezing
   text into a column on small screens. */
.sl-measure { max-width: 75%; }
@media (max-width: 991.98px) { .sl-measure { max-width: none; } }
.sl-container-narrow { max-width: 720px; }
.bg-parchment-2 { background: var(--sl-parchment-2); }
.sl-divider { height: 1px; background: var(--sl-line); border: 0; margin: 1.5rem 0; }
.sl-footer { color: var(--sl-muted); font-size: var(--sl-text-sm); }
.sl-footer a { color: var(--sl-ink-soft); }
.progress { background: var(--sl-parchment-2); border-radius: 999px; height: 8px; }
.progress-bar { border-radius: 999px; background: var(--sl-accent); }
.min-w-0 { min-width: 0; }
.sl-eyebrow { font-size: var(--sl-text-2xs); font-weight: 600; text-transform: uppercase; letter-spacing: .1em; color: var(--sl-muted); }

/* Homepage hero art: sits in the right-hand column of the split hero,
   left-aligned text opposite it. Fills the column width at its own aspect
   ratio (not a fixed square), so it works for a wide scene illustration as
   well as a squarer mascot. */
.sl-hero-shot {
    display: block; width: 100%; max-width: 440px; height: auto;
    margin: 0 auto;
    border: 1px solid var(--sl-line-strong);
    border-radius: var(--sl-radius-lg);
    overflow: hidden;
}
.sl-hero-mascot {
    display: block;
    width: 100%;
    height: auto;
    margin: 0 auto;
    border-radius: var(--sl-radius-lg);
}

.sl-step-num {
    font-family: var(--sl-serif); font-size: var(--sl-display-4); font-weight: 600;
    color: var(--sl-accent); background: var(--sl-accent-soft);
    width: 48px; height: 48px; border-radius: 13px;
    display: inline-flex; align-items: center; justify-content: center;
}

/* --- Provider / integration marks --------------------------------------- */
.sl-provider-mark {
    flex: 0 0 auto;
    width: 46px; height: 46px; border-radius: 13px;
    background: linear-gradient(150deg, var(--sl-accent), var(--sl-accent-dark));
    color: #fff;
    display: inline-flex; align-items: center; justify-content: center;
    font-family: var(--sl-serif); font-weight: 600; font-size: var(--sl-display-4);
    box-shadow: 0 6px 14px -8px rgba(13, 22, 27, .4);
}
.sl-provider-mark-sm {
    width: 32px; height: 32px; border-radius: 9px; font-size: var(--sl-text-base);
    box-shadow: none;
}
.sl-avatar {
    flex: 0 0 auto;
    width: 40px; height: 40px; border-radius: 50%;
    background: var(--sl-accent-soft); color: var(--sl-accent-dark);
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 600; font-size: var(--sl-text-sm);
}
