/* ===========================================================================
   EmbedSheets v2 - SaaS admin design system
   ---------------------------------------------------------------------------
   Scope: the SaaS dashboard and calculator builder only.

   The published calculator frontend has its own, completely separate theme
   system driven by --calc-* variables (see readme/SaaS_Layout_Calculator_
   Theme_System.docx). Never style the calculator frontend from this file.
   =========================================================================== */

:root {
    /* Brand */
    /*--es-primary:          #5b5bd6;
    --es-primary-hover:    #4f4fc4;
    --es-primary-active:   #4444ad;
    */

    --es-primary: #00a862;
    --es-primary-hover: #05cf7b;
    --es-primary-active: #00b167;

    /*--es-primary-soft:     #eef0fd;*/
    --es-primary-soft: #00c1711c;

    /*
     * Everything below is derived from the brand rather than picked
     * separately, because they only ever appear together: text and a border on
     * a --es-primary-soft panel, a focus ring, the second stop of a brand
     * gradient. When these were independent hex values the brand changed and
     * they did not, leaving blue text sitting on green.
     */
    --es-primary-ring:     rgba(0, 168, 98, 0.18);
    --es-primary-strong:   #046b41;   /* text on --es-primary-soft */
    --es-primary-border:   #b4e6cf;   /* border on --es-primary-soft */
    --es-accent:           #05cf7b;   /* the lighter end of a brand gradient */

    /* Neutrals */
    --es-bg:               #f6f8fb;
    --es-surface:          #ffffff;
    --es-surface-alt:      #fafbfc;
    --es-border:           #e3e8ef;
    --es-border-strong:    #cdd5e0;

    /* Text */
    --es-text:             #1a2231;
    --es-text-muted:       #5c6b82;
    --es-text-subtle:      #8695ab;
    --es-heading:          #0f172a;

    /* Status */
    --es-success:          #0f8a5f;
    --es-success-soft:     #e6f6ef;
    --es-warning:          #b25e09;
    --es-warning-soft:     #fdf3e6;
    --es-danger:           #cf3b3b;
    --es-danger-soft:      #fdeded;
    --es-danger-strong:    #a52f2f;   /* text on --es-danger-soft */
    --es-danger-border:    #f5c9c9;   /* border on --es-danger-soft */

    /* Shape */
    --es-radius-sm:        6px;
    --es-radius:           8px;
    --es-radius-lg:        12px;
    --es-radius-xl:        16px;

    /* Elevation - kept subtle, Stripe-style */
    --es-shadow-xs:        0 1px 2px rgba(16, 24, 40, 0.05);
    --es-shadow-sm:        0 1px 3px rgba(16, 24, 40, 0.08), 0 1px 2px rgba(16, 24, 40, 0.04);
    --es-shadow-md:        0 4px 12px rgba(16, 24, 40, 0.08);
    --es-shadow-lg:        0 12px 32px rgba(16, 24, 40, 0.12);

    --es-sidebar-width:    248px;
    --es-topbar-height:    64px;

    --es-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --es-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* ---------------------------------------------------------------------------
   Reset
   --------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    font-family: var(--es-font);
    font-size: 15px;
    line-height: 1.55;
    color: var(--es-text);
    background: var(--es-bg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4 {
    margin: 0 0 0.5em;
    color: var(--es-heading);
    font-weight: 640;
    line-height: 1.3;
    letter-spacing: -0.011em;
}

h1 { font-size: 26px; }
h2 { font-size: 20px; }
h3 { font-size: 16px; }

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

a { color: var(--es-primary); text-decoration: none; }
a:hover { text-decoration: underline; }

img { max-width: 100%; }

/* ---------------------------------------------------------------------------
   Layout: sidebar + content
   --------------------------------------------------------------------------- */

.es-shell { display: flex; min-height: 100vh; }

.es-sidebar {
    width: var(--es-sidebar-width);
    flex: 0 0 var(--es-sidebar-width);
    background: var(--es-surface);
    border-right: 1px solid var(--es-border);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
}

.es-sidebar__brand {
    display: flex;
    align-items: center;
    gap: 10px;
    height: var(--es-topbar-height);
    padding: 0 20px;
    border-bottom: 1px solid var(--es-border);
    font-weight: 660;
    font-size: 16px;
    color: var(--es-heading);
    letter-spacing: -0.02em;
    overflow: hidden;
}

.es-sidebar__brand:hover { text-decoration: none; }

.es-logo {
    width: 28px;
    height: 28px;
    border-radius: var(--es-radius-sm);
    background: linear-gradient(135deg, var(--es-primary) 0%, var(--es-accent) 100%);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 14px;
    font-weight: 700;
    flex: 0 0 28px;
}

.es-nav { padding: 16px 12px; flex: 1; overflow-y: auto; }

.es-nav__label {
    padding: 0 10px;
    margin: 18px 0 6px;
    font-size: 11px;
    font-weight: 620;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--es-text-subtle);
}
.es-nav__label:first-child { margin-top: 0; }

.es-nav__item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    margin-bottom: 2px;
    border-radius: var(--es-radius-sm);
    color: var(--es-text-muted);
    font-size: 14px;
    font-weight: 520;
    transition: background-color .12s ease, color .12s ease;
}

.es-nav__item:hover { background: var(--es-surface-alt); color: var(--es-text); text-decoration: none; }
.es-nav__item.is-active { background: var(--es-primary-soft); color: var(--es-primary); font-weight: 580; }
.es-nav__item svg { width: 17px; height: 17px; flex: 0 0 17px; }

.es-sidebar__footer { padding: 12px; border-top: 1px solid var(--es-border); }

.es-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.es-topbar {
    height: var(--es-topbar-height);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 0 28px;
    background: var(--es-surface);
    border-bottom: 1px solid var(--es-border);
    position: sticky;
    top: 0;
    z-index: 20;
}

.es-topbar__title { font-size: 15px; font-weight: 600; color: var(--es-heading); }
.es-topbar__actions { display: flex; align-items: center; gap: 12px; }

.es-content { padding: 28px; max-width: 1180px; width: 100%; }

.es-page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
    margin-bottom: 24px;
    flex-wrap: wrap;
}

.es-page-head p { color: var(--es-text-muted); margin: 4px 0 0; }

/* ---------------------------------------------------------------------------
   Cards
   --------------------------------------------------------------------------- */

.es-card {
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-lg);
    box-shadow: var(--es-shadow-xs);
}

.es-card__header {
    padding: 18px 22px;
    border-bottom: 1px solid var(--es-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.es-card__header h3 { margin: 0; }
.es-card__body { padding: 22px; }

.es-grid { display: grid; gap: 20px; }
.es-grid--2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.es-grid--3 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }

/* Stat tile */
.es-stat__label {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--es-text-subtle);
    margin-bottom: 6px;
}
.es-stat__value { font-size: 26px; font-weight: 660; color: var(--es-heading); letter-spacing: -0.02em; }
.es-stat__hint { font-size: 13px; color: var(--es-text-muted); margin-top: 4px; }

/* ---------------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------------- */

.es-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 9px 16px;
    border: 1px solid transparent;
    border-radius: var(--es-radius);
    font-family: inherit;
    font-size: 14px;
    font-weight: 560;
    line-height: 1.2;
    cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease, box-shadow .12s ease;
    white-space: nowrap;
}

.es-btn:hover { text-decoration: none; }
.es-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--es-primary-ring); }
.es-btn:disabled, .es-btn.is-disabled { opacity: .55; cursor: not-allowed; }

.es-btn--primary { background: var(--es-primary); color: #fff; box-shadow: var(--es-shadow-xs); }
.es-btn--primary:hover { background: var(--es-primary-hover); color: #fff; }
.es-btn--primary:active { background: var(--es-primary-active); }

/*
 * Every button is tinted, not white.
 *
 * A white box with a thin border on a white panel reads as a label with a line
 * round it, and a borderless one reads as text - so Copy, Open it and Save
 * name were being scrolled past. The primary action stays solid; everything
 * else is the same colour at a tenth of the strength, which says "button, but
 * not the one you came here for" without needing a second colour to say it.
 */
.es-btn--secondary {
    background: var(--es-primary-soft);
    color: var(--es-primary-strong);
    border-color: var(--es-primary-border);
    box-shadow: var(--es-shadow-xs);
}

.es-btn--secondary:hover {
    background: var(--es-primary-ring);
    color: var(--es-primary-strong);
}

/*
 * The quiet ones - Cancel, Close, the small icon buttons - get the same tint
 * without the shadow. They were transparent, which is the clearest possible
 * way of not looking like a button.
 */
.es-btn--ghost {
    background: var(--es-primary-soft);
    color: var(--es-primary-strong);
    border-color: var(--es-primary-border);
}

.es-btn--ghost:hover {
    background: var(--es-primary-ring);
    color: var(--es-primary-strong);
}

/*
 * Anything that removes something. Named after both of the above so it wins
 * whichever it is combined with - a Delete button is a Delete button whether
 * it was written as a ghost or a secondary one.
 */
.es-btn--danger,
.es-btn--ghost.es-btn--danger,
.es-btn--secondary.es-btn--danger {
    background: var(--es-danger-soft);
    color: var(--es-danger-strong);
    border-color: var(--es-danger-border);
}

.es-btn--danger:hover,
.es-btn--ghost.es-btn--danger:hover,
.es-btn--secondary.es-btn--danger:hover {
    background: #fbdcdc;
    color: var(--es-danger-strong);
}

.es-btn--danger:focus-visible { box-shadow: 0 0 0 3px rgba(207, 59, 59, .22); }

.es-btn--lg { padding: 12px 20px; font-size: 15px; }
.es-btn--sm { padding: 6px 11px; font-size: 13px; }
.es-btn--block { width: 100%; }

/* ---------------------------------------------------------------------------
   Tables
   --------------------------------------------------------------------------- */

.es-table { width: 100%; border-collapse: collapse; font-size: 14px; }

.es-table thead th {
    padding: 11px 22px;
    text-align: left;
    font-size: 11.5px;
    font-weight: 620;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--es-text-subtle);
    background: var(--es-surface-alt);
    border-bottom: 1px solid var(--es-border);
    white-space: nowrap;
}

.es-table tbody td { padding: 14px 22px; border-bottom: 1px solid var(--es-border); vertical-align: middle; }
.es-table tbody tr:last-child td { border-bottom: 0; }
.es-table tbody tr:hover { background: var(--es-surface-alt); }

.es-table__name { font-weight: 580; color: var(--es-heading); }
.es-table__name:hover { color: var(--es-primary); text-decoration: none; }

.es-table__actions { text-align: right; white-space: nowrap; }
.es-table__actions .es-btn { margin-left: 4px; }

/*
 * A table inside a card sits flush against its edges - the 22px on the cells
 * is the card's padding, which is why it goes in a wrapper of its own rather
 * than in .es-card__body. Inside the body it was indented by both and, worse,
 * a cell it could not shrink (a long slug in a <code>) pushed the whole table
 * out past the card's right-hand border with nothing to stop it.
 */
.es-tablewrap {
    overflow-x: auto;
    border-radius: 0 0 var(--es-radius-lg) var(--es-radius-lg);
}

/* An address is one long unbroken word. Left alone it sets the column's
   minimum width and everything else has to fit around it. */
.es-tablewrap code { overflow-wrap: anywhere; }

@media (max-width: 860px) {
    .es-table thead { display: none; }
    .es-table tbody tr { display: block; border-bottom: 1px solid var(--es-border); padding: 12px 4px; }
    .es-table tbody td { display: block; border: 0; padding: 4px 16px; }
    .es-table__actions { text-align: left; padding-top: 10px !important; }
    .es-table__actions .es-btn { margin: 0 4px 4px 0; }
}

/* ---------------------------------------------------------------------------
   Badges & alerts
   --------------------------------------------------------------------------- */

.es-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 580;
    line-height: 1.5;
}

.es-badge--neutral { background: var(--es-surface-alt); color: var(--es-text-muted); border: 1px solid var(--es-border); }
.es-badge--primary { background: var(--es-primary-soft); color: var(--es-primary); }
.es-badge--success { background: var(--es-success-soft); color: var(--es-success); }
.es-badge--warning { background: var(--es-warning-soft); color: var(--es-warning); }
.es-badge--danger  { background: var(--es-danger-soft);  color: var(--es-danger); }

.es-alert {
    display: flex;
    gap: 12px;
    padding: 14px 16px;
    border-radius: var(--es-radius);
    border: 1px solid;
    font-size: 14px;
    margin-bottom: 20px;
}

.es-alert--info    { background: var(--es-primary-soft); border-color: var(--es-primary-border); color: var(--es-primary-strong); }
.es-alert--success { background: var(--es-success-soft); border-color: #c3ead9; color: #0b6b4a; }
.es-alert--warning { background: var(--es-warning-soft); border-color: #f5ddb9; color: #8a4a07; }
.es-alert--danger  { background: var(--es-danger-soft);  border-color: #f5c9c9; color: #a52f2f; }
.es-alert strong { font-weight: 620; }

/* ---------------------------------------------------------------------------
   Forms
   --------------------------------------------------------------------------- */

.es-field { margin-bottom: 18px; }

.es-label {
    display: block;
    margin-bottom: 6px;
    font-size: 13px;
    font-weight: 580;
    color: var(--es-text);
}

.es-input, .es-select, .es-textarea {
    width: 100%;
    padding: 9px 12px;
    font-family: inherit;
    font-size: 14px;
    color: var(--es-text);
    background: var(--es-surface);
    border: 1px solid var(--es-border-strong);
    border-radius: var(--es-radius);
    box-shadow: var(--es-shadow-xs);
    transition: border-color .12s ease, box-shadow .12s ease;
}

.es-input:focus, .es-select:focus, .es-textarea:focus {
    outline: none;
    border-color: var(--es-primary);
    box-shadow: 0 0 0 3px var(--es-primary-ring);
}

.es-input:disabled, .es-select:disabled, .es-textarea:disabled {
    background: var(--es-surface-alt);
    color: var(--es-text-subtle);
    cursor: not-allowed;
}

.es-input::placeholder { color: var(--es-text-subtle); }
.es-help { margin-top: 6px; font-size: 13px; color: var(--es-text-muted); }

/* ---------------------------------------------------------------------------
   Avatar & user menu
   --------------------------------------------------------------------------- */

.es-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--es-primary-soft);
    color: var(--es-primary);
    display: grid;
    place-items: center;
    font-size: 13px;
    font-weight: 620;
    flex: 0 0 32px;
    border: 1px solid var(--es-border);
}

.es-user {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: var(--es-radius);
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
}

.es-user__meta { min-width: 0; flex: 1; }
.es-user__name {
    font-size: 13px;
    font-weight: 580;
    color: var(--es-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.es-user__email {
    font-size: 12px;
    color: var(--es-text-subtle);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.es-linkbtn {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-size: 12px;
    color: var(--es-text-muted);
    cursor: pointer;
    text-decoration: underline;
}
.es-linkbtn:hover { color: var(--es-danger); }

/* ---------------------------------------------------------------------------
   Template picker
   --------------------------------------------------------------------------- */

.es-template {
    display: block;
    width: 100%;
    text-align: left;
    padding: 22px;
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-lg);
    box-shadow: var(--es-shadow-xs);
    font-family: inherit;
    cursor: pointer;
    transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}

.es-template:hover:not(:disabled) {
    border-color: var(--es-primary);
    box-shadow: var(--es-shadow-md);
    transform: translateY(-1px);
}

.es-template:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--es-primary-ring); }
.es-template:disabled { opacity: .55; cursor: not-allowed; }
.es-template.is-busy { opacity: .7; }

.es-template h3 { margin: 0 0 6px; font-size: 15.5px; }
.es-template p { color: var(--es-text-muted); font-size: 13.5px; margin: 0 0 14px; }
.es-template .es-badge { margin-right: 6px; }

.es-template__icon {
    width: 38px;
    height: 38px;
    margin-bottom: 14px;
    border-radius: var(--es-radius);
    background: var(--es-primary-soft);
    color: var(--es-primary);
    display: grid;
    place-items: center;
}
.es-template__icon svg { width: 19px; height: 19px; }

/*
 * Blank stands alone above the templates, so it is laid out along the row
 * rather than down a card: icon, then the words beside it, then the badge at
 * the far end. Stacked, a single full-width card is mostly empty space.
 */
.es-template--blank {
    display: flex;
    align-items: center;
    gap: 18px;
    margin-bottom: 34px;
}

.es-template--blank .es-template__icon { margin-bottom: 0; flex: 0 0 auto; background: var(--es-surface-alt); color: var(--es-text-muted); }
.es-template--blank .es-template__body { flex: 1 1 auto; min-width: 0; }
.es-template--blank h3 { margin-bottom: 3px; }
.es-template--blank p { margin: 0; }
.es-template--blank .es-badge { margin-right: 0; flex: 0 0 auto; }

/* The templates get their own heading and a filter beside it. */
.es-templates-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}

.es-templates-head h2 { margin: 0 0 4px; font-size: 19px; }
.es-templates-head p { margin: 0; color: var(--es-text-muted); font-size: 13.5px; }

.es-templates-filter { display: flex; align-items: center; gap: 9px; }

.es-templates-filter > span {
    color: var(--es-text-muted);
    font-size: 13px;
    white-space: nowrap;
}

.es-templates-filter select {
    min-width: 210px;
    padding: 9px 11px;
    font-family: inherit;
    font-size: 13.5px;
    color: var(--es-text);
    background: var(--es-surface);
    border: 1px solid var(--es-border-strong);
    border-radius: var(--es-radius);
    cursor: pointer;
}

.es-templates-filter select:focus {
    outline: none;
    border-color: var(--es-primary);
    box-shadow: 0 0 0 3px var(--es-primary-ring);
}

/*
 * Announced, not built. Dimmer than a live card but not as faint as the
 * disabled state used for "you have hit your plan limit" - this one is not
 * telling the owner off, it is saying "not yet".
 */
.es-template--soon { opacity: .72; }
.es-template--soon:disabled { cursor: default; }
.es-template--soon .es-template__icon { background: var(--es-surface-alt); color: var(--es-text-subtle); }

.es-templates-none {
    margin: 6px 0 0;
    color: var(--es-text-muted);
    font-size: 14px;
}

@media (max-width: 560px) {
    .es-templates-head { align-items: stretch; }
    .es-templates-filter { justify-content: space-between; }
    .es-templates-filter select { flex: 1 1 auto; min-width: 0; }
    .es-template--blank { flex-wrap: wrap; gap: 12px; }
}

/* ---------------------------------------------------------------------------
   Empty state
   --------------------------------------------------------------------------- */

.es-empty { text-align: center; padding: 44px 24px; }
.es-empty__icon {
    width: 46px;
    height: 46px;
    margin: 0 auto 14px;
    border-radius: var(--es-radius-lg);
    background: var(--es-primary-soft);
    color: var(--es-primary);
    display: grid;
    place-items: center;
}
.es-empty h3 { margin-bottom: 6px; }
.es-empty p { color: var(--es-text-muted); max-width: 420px; margin: 0 auto 20px; }

/* ---------------------------------------------------------------------------
   Auth screen (login)
   --------------------------------------------------------------------------- */

.es-auth {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 32px 20px;
    background:
        radial-gradient(1000px 500px at 50% -10%, #eceefc 0%, rgba(236, 238, 252, 0) 62%),
        var(--es-bg);
}

.es-auth__box { width: 100%; max-width: 412px; }

.es-auth__brand {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-bottom: 22px;
    font-size: 19px;
    font-weight: 660;
    color: var(--es-heading);
    letter-spacing: -0.02em;
}

.es-auth__card {
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-xl);
    box-shadow: var(--es-shadow-lg);
    padding: 34px 32px;
    text-align: center;
}

.es-auth__card h1 { font-size: 21px; margin-bottom: 6px; }
.es-auth__card > p { color: var(--es-text-muted); font-size: 14px; margin-bottom: 26px; }

/* Google button follows Google's brand guidance: white surface, neutral
   border, official mark, unmodified wordmark text. */
.es-google-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 11px;
    width: 100%;
    padding: 12px 18px;
    background: #fff;
    border: 1px solid var(--es-border-strong);
    border-radius: var(--es-radius);
    box-shadow: var(--es-shadow-sm);
    color: #3c4043;
    font-family: inherit;
    font-size: 15px;
    font-weight: 560;
    cursor: pointer;
    transition: background-color .12s ease, box-shadow .12s ease;
}

.es-google-btn:hover { background: #f8f9fa; box-shadow: var(--es-shadow-md); text-decoration: none; color: #3c4043; }
.es-google-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--es-primary-ring); }
.es-google-btn svg { width: 18px; height: 18px; flex: 0 0 18px; }

.es-auth__note {
    margin-top: 22px;
    padding-top: 20px;
    border-top: 1px solid var(--es-border);
    font-size: 13px;
    color: var(--es-text-muted);
}

.es-auth__trial {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 22px;
    padding: 5px 12px;
    border-radius: 999px;
    background: var(--es-success-soft);
    color: var(--es-success);
    font-size: 12.5px;
    font-weight: 580;
}

.es-auth__footer { text-align: center; margin-top: 20px; font-size: 12.5px; color: var(--es-text-subtle); }

/* ---------------------------------------------------------------------------
   Setup / diagnostic list (shown when Google credentials are missing)
   --------------------------------------------------------------------------- */

.es-steps { text-align: left; margin: 0; padding-left: 20px; font-size: 13.5px; color: var(--es-text-muted); }
.es-steps li { margin-bottom: 8px; }
.es-steps code, .es-code {
    font-family: var(--es-font-mono);
    font-size: 12.5px;
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    border-radius: 4px;
    padding: 1px 5px;
    color: var(--es-text);
    word-break: break-all;
}

/* ---------------------------------------------------------------------------
   Utilities
   --------------------------------------------------------------------------- */

.es-muted { color: var(--es-text-muted); }
.es-mb-0 { margin-bottom: 0; }
.es-mt-16 { margin-top: 16px; }
.es-flex { display: flex; align-items: center; gap: 10px; }
.es-flex-between { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.es-sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------------------
   Responsive
   --------------------------------------------------------------------------- */

@media (max-width: 900px) {
    .es-shell { flex-direction: column; }

    .es-sidebar {
        width: 100%;
        flex: none;
        height: auto;
        position: static;
        border-right: 0;
        border-bottom: 1px solid var(--es-border);
    }

    .es-nav { display: flex; gap: 4px; overflow-x: auto; padding: 10px 12px; }
    .es-nav__label { display: none; }
    .es-nav__item { white-space: nowrap; margin-bottom: 0; }
    .es-sidebar__footer { display: none; }

    .es-topbar { padding: 0 18px; }
    .es-content { padding: 20px 18px; }
}

@media (max-width: 560px) {
    .es-topbar__title { display: none; }
    .es-auth__card { padding: 26px 20px; }
    .es-card__body, .es-card__header { padding: 16px; }
}


/* ---------------------------------------------------------------------------
   Analytics layout, filters and lead details
   --------------------------------------------------------------------------- */

.es-analytics {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    gap: 20px;
    align-items: start;
}

@media (max-width: 1000px) {
    .es-analytics { grid-template-columns: 1fr; }
}

/* Range switch above the chart */
.es-range { display: inline-flex; gap: 2px; padding: 3px; background: var(--es-surface-alt);
    border: 1px solid var(--es-border); border-radius: var(--es-radius); }
.es-range__option { padding: 4px 11px; border-radius: var(--es-radius-sm); font-size: 12.5px;
    font-weight: 540; color: var(--es-text-muted); }
.es-range__option:hover { color: var(--es-text); text-decoration: none; }
.es-range__option.is-active { background: var(--es-surface); color: var(--es-primary);
    box-shadow: var(--es-shadow-xs); }

/* Filter row */
.es-filters { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.es-filters__field { display: flex; flex-direction: column; gap: 5px; min-width: 170px; }
.es-filters__field--grow { flex: 1; min-width: 200px; }
.es-filters__field label { font-size: 12px; font-weight: 560; color: var(--es-text-muted); }
.es-filters__actions { display: flex; gap: 8px; }

@media (max-width: 640px) {
    .es-filters__field, .es-filters__field--grow { min-width: 100%; }
    .es-filters__actions { width: 100%; }
    .es-filters__actions .es-btn { flex: 1; }
}

/* Lead detail row */
/* The summary row is a control: the whole thing opens the detail below it,
   so it has to look like something you can click before you click it. */
.es-lead-row { cursor: pointer; }
.es-lead-row:hover { background: var(--es-surface-alt); }
.es-lead-row:focus-visible { outline: 2px solid var(--es-primary); outline-offset: -2px; }
.es-lead-row.is-open { background: var(--es-surface-alt); }

/* A link inside the row keeps its own meaning - clicking an address should
   compose an email, not expand a panel - so it says so with the cursor. */
.es-lead-row a { cursor: pointer; position: relative; z-index: 1; }

.es-lead-detail > td { background: var(--es-surface-alt); padding: 16px 22px !important; }
.es-lead-detail__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 26px; }
.es-lead-detail__row { display: flex; justify-content: space-between; gap: 14px;
    padding: 5px 0; font-size: 13px; border-bottom: 1px solid var(--es-border); }
.es-lead-detail__row:last-child { border-bottom: 0; }
.es-lead-detail__row span { color: var(--es-text-muted); }
.es-lead-detail__row strong { color: var(--es-text); text-align: right; overflow-wrap: anywhere; }

/* Several attachments under one answer: one per line, so two long filenames
   do not run together into something that reads as a single name. */
.es-lead-detail__files { display: flex; flex-direction: column; gap: 2px; align-items: flex-end; }

@media (max-width: 700px) {
    .es-lead-detail__grid { grid-template-columns: 1fr; gap: 18px; }
}

/* Pager */
.es-pager { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 18px; }
.es-pager__info { font-size: 13px; color: var(--es-text-muted); }

/* ---------------------------------------------------------------------------
   Brand marks
   Sized by height with width:auto, so swapping in a logo of a different aspect
   ratio needs no CSS change - only the constant in config/app.php.
   --------------------------------------------------------------------------- */

/* The stacked lock-up at the top of the dashboard sidebar. It contains the
   wordmark, so nothing is printed beside it - the row is the logo. */
.es-brandmark {
    height: 40px;
    width: auto;
    max-width: 100%;
    object-fit: contain;
    object-position: left center;
    display: block;
}

/* The full lock-up on the sign-in screen. It carries the wordmark itself, so
   no product name is printed next to it. */
.es-brandwide {
    height: 34px;
    width: auto;
    max-width: 100%;
    object-fit: contain;
    display: block;
}

/* A block of machine output - a test response, a payload - shown for reading
   rather than editing. Scrolls in both directions instead of stretching the
   card it sits in. */
.es-code-block {
    max-height: 260px;
    overflow: auto;
    margin: 0 0 12px;
    padding: 12px 14px;
    font-family: var(--es-font-mono);
    font-size: 12px;
    line-height: 1.55;
    color: var(--es-text-muted);
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius);
    white-space: pre;
}

/* ---------------------------------------------------------------------------
   Bulk selection
   --------------------------------------------------------------------------- */

.es-table__pick { width: 42px; text-align: center; cursor: pointer; }
.es-table__pick input { cursor: pointer; accent-color: var(--es-primary); }

.es-table tbody tr.is-picked { background: var(--es-primary-soft); }

/* Appears only when something is selected, so it never takes space it has not
   earned. */
.es-bulkbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 11px 16px;
    margin-bottom: 12px;
    background: var(--es-primary-soft);
    border: 1px solid var(--es-primary-border);
    border-radius: var(--es-radius);
}

.es-bulkbar[hidden] { display: none; }
.es-bulkbar__count { font-size: 13px; font-weight: 560; color: var(--es-primary); }
.es-bulkbar__actions { display: flex; gap: 8px; }

/* --- the confirmation --- */

.es-confirm {
    position: fixed;
    inset: 0;
    z-index: 300;
    background: rgba(16, 24, 40, .45);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}

.es-confirm__box {
    width: 100%;
    max-width: 440px;
    background: var(--es-surface);
    border-radius: var(--es-radius-xl);
    box-shadow: var(--es-shadow-lg);
    padding: 24px;
}

.es-confirm__box h2 { margin: 0 0 8px; font-size: 17px; }
.es-confirm__box p { margin: 0 0 14px; font-size: 13.5px; line-height: 1.6; color: var(--es-text-muted); }

/* Naming what is about to go is the point of this dialog, so the list is the
   thing that scrolls rather than the page behind it. */
.es-confirm__list {
    margin: 0 0 18px;
    padding: 10px 14px 10px 30px;
    max-height: 180px;
    overflow-y: auto;
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font-size: 13px;
    line-height: 1.7;
}

.es-confirm__more { list-style: none; margin-left: -16px; color: var(--es-text-subtle); font-style: italic; }
.es-confirm__actions { display: flex; justify-content: flex-end; gap: 8px; }

/* ---------------------------------------------------------------------------
   Billing & Plan
   --------------------------------------------------------------------------- */

/* .es-card has no padding of its own - it expects __header and __body, which
   this card does not use - so it is set here. */
.es-billing-now {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
    padding: 24px 26px;
    margin-bottom: 34px;
}

.es-billing-now__main { flex: 1 1 320px; min-width: 0; }
.es-billing-now__main h2 { margin: 12px 0 6px; font-size: 21px; }
.es-billing-now__main p { margin: 0; color: var(--es-text-muted); font-size: 14px; }

/* The renewal date is the single thing most people opened this page to find. */
.es-billing-now__note { margin-top: 12px !important; color: var(--es-text) !important; }

.es-billing-now__side { flex: 0 0 auto; text-align: right; }
.es-billing-now__small { margin: 8px 0 0; max-width: 220px; color: var(--es-text-subtle); font-size: 11.5px; }

.es-section-title { margin: 0 0 16px; font-size: 17px; }

/*
 * The cards stretch to match each other, and each lays itself out as a column
 * so the button can be pinned to the bottom. Without both, a plan with a
 * shorter feature list left its button floating half way up the row.
 */
.es-plans { align-items: stretch; }

.es-plan {
    display: flex;
    flex-direction: column;
    padding: 24px 22px;
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-lg);
    box-shadow: var(--es-shadow-xs);
}

.es-plan.is-current { border-color: var(--es-primary); box-shadow: 0 0 0 3px var(--es-primary-ring); }
.es-plan h3 { margin: 0 0 10px; font-size: 15px; font-weight: 600; color: var(--es-text-muted); }

.es-plan__price { margin: 0 0 20px; display: flex; align-items: baseline; gap: 3px; }
.es-plan__price strong { font-size: 32px; letter-spacing: -.02em; color: var(--es-text); }
.es-plan__price span { color: var(--es-text-subtle); font-size: 13px; }

.es-plan__features {
    list-style: none;
    margin: 0 0 22px;
    padding: 0 0 2px;
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.es-plan__features li {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--es-text-muted);
}

/* The tick. A filled circle in the brand colour with a white check cut
   through it, drawn inline so it never depends on an icon font being
   present - which on these pages it is not. */
.es-tick { flex: 0 0 auto; width: 16px; height: 16px; margin-top: 1px; }
.es-tick circle { fill: var(--es-primary); }

/* The one line that differs between plans is the one worth reading. */
.es-plan__features li.is-key {
    padding-bottom: 11px;
    margin-bottom: 2px;
    border-bottom: 1px solid var(--es-border);
    color: var(--es-text);
    font-weight: 600;
    font-size: 13.5px;
}

/* margin-top:auto is what holds the buttons on one line across the row. */
.es-plan__foot { margin-top: auto; }

.es-plan__current {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 10px;
    border-radius: var(--es-radius);
    background: var(--es-primary-soft);
    color: var(--es-primary-strong);
    font-size: 13.5px;
    font-weight: 600;
}

/* Said before they pay, not after. */
.es-plan__warn {
    margin: 10px 0 0;
    color: var(--es-danger);
    font-size: 11.5px;
    line-height: 1.45;
}

/*
 * Cancelling is a real button, not a link in the corner.
 *
 * It was a quiet ghost link, which is the pattern used to make leaving hard to
 * find. Somebody who wants to stop paying should be able to, without hunting -
 * a cancel button that hides is how a product collects chargebacks instead of
 * cancellations.
 */
.es-cancel-btn {
    background: #fff;
    border: 1px solid var(--es-danger);
    color: var(--es-danger);
    font-weight: 600;
}

.es-cancel-btn:hover { background: var(--es-danger); border-color: var(--es-danger); color: #fff; }
.es-cancel-btn:disabled { opacity: .6; cursor: not-allowed; }
.es-billing-foot { margin-top: 26px; color: var(--es-text-subtle); font-size: 12.5px; }

/* Signed in as somebody else. Loud on purpose: the danger of this feature is
   forgetting it is on, so it must not be possible to overlook. */
.es-impersonating {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    padding: 10px 28px;
    background: #b25e09;
    color: #fff;
    font-size: 13px;
}

.es-impersonating .es-btn {
    background: rgba(255, 255, 255, .18);
    color: #fff;
    border-color: rgba(255, 255, 255, .35);
}

.es-impersonating .es-btn:hover { background: rgba(255, 255, 255, .28); }

/* The admin portal's tab strip, shared by every admin screen. */
.es-admin-tabs {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-bottom: 22px;
    border-bottom: 1px solid var(--es-border);
}

.es-admin-tab {
    padding: 9px 14px;
    color: var(--es-text-muted);
    font-size: 13.5px;
    font-weight: 550;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.es-admin-tab:hover { color: var(--es-text); text-decoration: none; }
.es-admin-tab.is-active { color: var(--es-primary); border-bottom-color: var(--es-primary); }

/* The way out sits apart from the pages within the portal. */
.es-admin-tab--out { margin-left: auto; color: var(--es-text-subtle); font-size: 12.5px; }

/* Who takes the money. FastSpring is the merchant of record, so their mark
   belongs here: it is the name that appears on the card statement. Centred
   and given room - it was squeezed beside the text and read as a stray icon. */
.es-billing-foot {
    margin-top: 40px;
    padding-top: 28px;
    border-top: 1px solid var(--es-border);
    text-align: center;
}

.es-billing-foot p {
    margin: 14px 0 0;
    color: var(--es-text-subtle);
    font-size: 12.5px;
    line-height: 1.7;
}

.es-fs-badge {
    display: inline-block;
    padding: 12px 22px;
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius);
    transition: border-color .12s ease, box-shadow .12s ease;
}

.es-fs-badge:hover { border-color: var(--es-border-strong); box-shadow: var(--es-shadow-xs); }
.es-fs-badge img { display: block; height: 30px; width: auto; }

/* The middle plan, marked. position:relative so the tag can sit on the border
   rather than pushing the heading down and knocking the cards out of line. */
.es-plan { position: relative; }

.es-plan.is-popular {
    border-color: var(--es-primary);
    box-shadow: 0 0 0 1px var(--es-primary), var(--es-shadow-md);
}

.es-plan__tag {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 5px 13px;
    background: var(--es-primary);
    color: #fff;
    border-radius: 999px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* A popular plan that is also the current one keeps the current-plan ring:
   which plan you are ON matters more than which one we recommend. */
.es-plan.is-popular.is-current { box-shadow: 0 0 0 3px var(--es-primary-ring); }

/* An action that reads as part of the sentence it sits in. */
.es-linkish {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: var(--es-primary);
    text-decoration: underline;
    cursor: pointer;
}

.es-linkish:hover { color: var(--es-primary-hover); }
.es-linkish:disabled { opacity: .6; cursor: default; text-decoration: none; }

/* CRM integration: what is coming, and what to do until it does. */
.es-soon, .es-howto { padding: 26px; margin-bottom: 20px; }
.es-soon h2, .es-howto h2 { margin: 14px 0 10px; font-size: 19px; }
.es-soon p, .es-howto p { color: var(--es-text-muted); font-size: 14.5px; max-width: 68ch; }

.es-steps {
    margin: 18px 0 20px;
    padding: 0;
    list-style: none;
    counter-reset: step;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.es-steps li {
    counter-increment: step;
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 14px;
    color: var(--es-text);
}

/* Numbered from the counter rather than the markup, so the order cannot
   disagree with what is written. */
.es-steps li::before {
    content: counter(step);
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--es-primary-soft);
    color: var(--es-primary-strong);
    font-size: 12px;
    font-weight: 700;
}

.es-howto__more { margin: 0; font-size: 14px; }

/* Paid setup, offered after the free route rather than in place of it. */
.es-hire {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
    padding: 24px 26px;
    background: var(--es-primary-soft);
    border-color: var(--es-primary-border);
}

.es-hire__body { flex: 1 1 340px; min-width: 0; }
.es-hire h2 { margin: 0 0 8px; font-size: 17px; }
.es-hire p { margin: 0; color: var(--es-text-muted); font-size: 14px; max-width: 62ch; }
.es-hire .es-btn { flex: 0 0 auto; }

/* ---------------------------------------------------------------------------
   Documentation
   --------------------------------------------------------------------------- */

.es-docs { display: flex; align-items: flex-start; gap: 34px; }

/* The sidebar follows the reader down the page: the topic list is how you move
   around a document this long, and scrolling away from it strands you. */
.es-docs__nav {
    flex: 0 0 258px;
    position: sticky;
    top: 88px;
    max-height: calc(100vh - 110px);
    overflow-y: auto;
    padding-right: 6px;
}

.es-docs__search { position: relative; margin-bottom: 18px; }

.es-docs__search input {
    width: 100%;
    padding: 10px 12px;
    font-family: inherit;
    font-size: 13.5px;
    color: var(--es-text);
    background: var(--es-surface);
    border: 1px solid var(--es-border-strong);
    border-radius: var(--es-radius);
}

.es-docs__search input:focus {
    outline: none;
    border-color: var(--es-primary);
    box-shadow: 0 0 0 3px var(--es-primary-ring);
}

.es-docs__results {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 30;
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius);
    box-shadow: var(--es-shadow-lg);
    overflow: hidden;
}

.es-docs__result { display: block; padding: 9px 12px; border-bottom: 1px solid var(--es-border); }
.es-docs__result:last-child { border-bottom: 0; }
.es-docs__result:hover { background: var(--es-surface-alt); text-decoration: none; }
.es-docs__result strong { display: block; font-size: 13px; color: var(--es-text); font-weight: 600; }
.es-docs__result span { font-size: 11.5px; color: var(--es-text-subtle); }
.es-docs__none { padding: 12px; font-size: 13px; color: var(--es-text-subtle); }

.es-docs__topic { border-bottom: 1px solid var(--es-border); }

.es-docs__topichead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 11px 4px;
    border: 0;
    background: none;
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--es-text);
    text-align: left;
    cursor: pointer;
}

.es-docs__topichead svg { width: 16px; height: 16px; flex: 0 0 auto; color: var(--es-text-subtle); transition: transform .15s ease; }
.es-docs__topic.is-open .es-docs__topichead svg { transform: rotate(90deg); }

/* Closed by default so the whole contents page is visible at once, rather
   than one topic filling the panel. */
.es-docs__sections { display: none; list-style: none; margin: 0; padding: 0 0 10px; }
.es-docs__topic.is-open .es-docs__sections { display: block; }

.es-docs__sections a {
    display: block;
    padding: 6px 4px 6px 14px;
    border-left: 2px solid var(--es-border);
    font-size: 13px;
    color: var(--es-text-muted);
}

.es-docs__sections a:hover { color: var(--es-text); text-decoration: none; }
.es-docs__sections a.is-current { border-left-color: var(--es-primary); color: var(--es-primary); font-weight: 600; }

.es-docs__body { flex: 1 1 auto; min-width: 0; max-width: 820px; }
.es-docs__intro { margin-bottom: 34px; }
.es-docs__intro p { color: var(--es-text-muted); margin: 6px 0 0; }

.es-docs__group { margin-bottom: 46px; }

.es-docs__grouptitle {
    margin: 0 0 20px;
    padding-bottom: 10px;
    border-bottom: 2px solid var(--es-primary);
    font-size: 21px;
}

/* scroll-margin so a linked section lands below the sticky top bar rather
   than underneath it. */
.es-doc { margin-bottom: 34px; scroll-margin-top: 90px; }
.es-doc h3 { display: flex; align-items: center; gap: 8px; margin: 0 0 12px; font-size: 17px; }
.es-doc__body { color: var(--es-text-muted); font-size: 14.5px; line-height: 1.7; }
.es-doc__body p { margin: 0 0 12px; }
.es-doc__body ul, .es-doc__body ol { margin: 0 0 14px; padding-left: 22px; }
.es-doc__body li { margin-bottom: 6px; }
.es-doc__body h4 { margin: 20px 0 10px; font-size: 14.5px; color: var(--es-text); }
.es-doc__body code { padding: 2px 5px; background: var(--es-surface-alt); border: 1px solid var(--es-border); border-radius: 4px; font-family: var(--es-font-mono); font-size: 12.5px; color: var(--es-text); }
.es-doc__body strong { color: var(--es-text); }

/* The anchor button: visible on hover, so it does not clutter every heading. */
.es-doc__link { opacity: 0; padding: 0 4px; border: 0; background: none; color: var(--es-text-subtle); font-size: 15px; cursor: pointer; transition: opacity .12s ease; }
.es-doc:hover .es-doc__link, .es-doc__link:focus { opacity: 1; }
.es-doc__link.is-done { color: var(--es-primary); }

.es-doc-steps { counter-reset: dstep; list-style: none; padding-left: 0 !important; }
.es-doc-steps li { counter-increment: dstep; position: relative; padding-left: 32px; margin-bottom: 9px; }
.es-doc-steps li::before {
    content: counter(dstep);
    position: absolute;
    left: 0;
    top: 1px;
    width: 22px;
    height: 22px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--es-primary-soft);
    color: var(--es-primary-strong);
    font-size: 11.5px;
    font-weight: 700;
}

.es-doc-note {
    margin: 14px 0;
    padding: 12px 15px;
    background: var(--es-warning-soft);
    border-left: 3px solid var(--es-warning);
    border-radius: var(--es-radius-sm);
    font-size: 13.5px;
    color: var(--es-text);
}

.es-doc-codewrap { position: relative; margin: 0 0 14px; }

.es-doc-code {
    margin: 0;
    padding: 14px 78px 14px 15px;
    overflow-x: auto;
    background: #1f2937;
    border-radius: var(--es-radius);
    color: #e5e7eb;
    font-family: var(--es-font-mono);
    font-size: 12.5px;
    line-height: 1.6;
    white-space: pre;
}

.es-doc-copy {
    position: absolute;
    top: 9px;
    right: 9px;
    padding: 5px 11px;
    border: 1px solid rgba(255, 255, 255, .22);
    border-radius: var(--es-radius-sm);
    background: rgba(255, 255, 255, .10);
    color: #fff;
    font-family: inherit;
    font-size: 11.5px;
    cursor: pointer;
}

.es-doc-copy:hover { background: rgba(255, 255, 255, .2); }
.es-doc-copy.is-done { background: var(--es-primary); border-color: var(--es-primary); }

.es-doc-fns { display: flex; flex-direction: column; gap: 14px; margin-bottom: 20px; }

.es-doc-fn {
    padding: 14px 16px;
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius);
}

.es-doc-fn > code { display: inline-block; margin-bottom: 6px; font-size: 13px; font-weight: 600; }
.es-doc-fn p { margin: 0 0 10px; font-size: 13.5px; }
.es-doc-fn .es-doc-codewrap { margin-bottom: 0; }

@media (max-width: 900px) {
    .es-docs { flex-direction: column; }
    .es-docs__nav { position: static; flex: 1 1 auto; width: 100%; max-height: none; }
}

/* Function reference: signature, what each argument means, then a worked case. */
.es-doc-fn__sig { display: inline-block; margin-bottom: 8px; font-size: 13px; font-weight: 600; }

.es-doc-args { width: 100%; margin: 0 0 14px; border-collapse: collapse; font-size: 13px; }
.es-doc-args th {
    width: 34%;
    padding: 7px 12px 7px 0;
    text-align: left;
    vertical-align: top;
    font-weight: 500;
    border-bottom: 1px solid var(--es-border);
}
.es-doc-args td {
    padding: 7px 0;
    vertical-align: top;
    color: var(--es-text-muted);
    border-bottom: 1px solid var(--es-border);
}
.es-doc-args tr:last-child th, .es-doc-args tr:last-child td { border-bottom: 0; }
.es-doc-args code { font-size: 12px; }

.es-doc-args__opt {
    margin-left: 4px;
    color: var(--es-text-subtle);
    font-size: 10.5px;
    font-style: italic;
}

.es-doc-fn__case { margin: 0 0 10px !important; font-size: 13.5px; }
.es-doc-fn .es-doc-note { margin-top: 12px; margin-bottom: 0; font-size: 12.5px; }

/* A function linked to directly must clear the sticky top bar, same as a
   section does. */
.es-doc-fn { scroll-margin-top: 90px; }

/* Language tabs on a code example. */
.es-doc-tabs { margin: 0 0 14px; }

.es-doc-tabs__bar {
    display: flex;
    gap: 2px;
    padding: 4px;
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius) var(--es-radius) 0 0;
    border-bottom: 0;
}

.es-doc-tabs__btn {
    padding: 6px 14px;
    border: 0;
    border-radius: var(--es-radius-sm);
    background: none;
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 550;
    color: var(--es-text-muted);
    cursor: pointer;
}

.es-doc-tabs__btn:hover { color: var(--es-text); }
.es-doc-tabs__btn.is-active { background: var(--es-surface); color: var(--es-primary); box-shadow: var(--es-shadow-xs); }

/* One pane at a time; the bar sits directly on the block. */
.es-doc-tab { display: none; }
.es-doc-tab.is-active { display: block; }
.es-doc-tabs .es-doc-codewrap { margin: 0; }
.es-doc-tabs .es-doc-code { border-radius: 0 0 var(--es-radius) var(--es-radius); }

/* Headings in the brand green, so the eye finds the structure while scanning
   a long document rather than reading for it. */
.es-docs__grouptitle { color: var(--es-primary-strong); }
.es-doc h3 { color: var(--es-primary); }
.es-doc__body h4 { color: var(--es-primary-strong); }

/* ---------------------------------------------------------------------------
 * The AI generation viewer (admin only)
 *
 * A long exchange read once while something is being diagnosed, so it goes
 * over the page rather than on it.
 * ------------------------------------------------------------------------- */

.es-aiview {
    position: fixed;
    inset: 0;
    z-index: 9000;
    background: rgba(16, 24, 40, .55);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}

.es-aiview[hidden] { display: none; }

.es-aiview__box {
    background: var(--es-surface);
    border-radius: var(--es-radius-md, 10px);
    box-shadow: var(--es-shadow-md);
    width: min(900px, 100%);
    height: min(88vh, 820px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.es-aiview__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-bottom: 1px solid var(--es-border);
}

.es-aiview__close {
    border: 0;
    background: none;
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    color: var(--es-text-subtle);
    padding: 0 4px;
}

.es-aiview__close:hover { color: var(--es-text); }

.es-aiview__body { flex: 1; overflow-y: auto; padding: 16px 18px; }

.es-aiview__body dl {
    display: grid;
    grid-template-columns: 130px 1fr;
    gap: 4px 12px;
    margin: 0 0 18px;
    font-size: 13px;
}

.es-aiview__body dt { color: var(--es-text-subtle); }
.es-aiview__body dd { margin: 0; color: var(--es-text); }

.es-aiview__body h4 {
    margin: 18px 0 6px;
    font-size: 12px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--es-text-subtle);
}

/*
 * Wrapped, not scrolled sideways. A prompt is prose and a payload is JSON that
 * has already been indented; a horizontal scrollbar on each of five blocks
 * makes the whole thing unreadable.
 */
.es-aiview__body pre {
    margin: 0;
    padding: 10px 12px;
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm, 6px);
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 11.5px;
    line-height: 1.55;
    white-space: pre-wrap;
    overflow-wrap: break-word;
    max-height: 340px;
    overflow-y: auto;
}

/* ---------------------------------------------------------------------------
 * The administration portal
 *
 * A side menu rather than a strip of tabs across the top. There are five
 * screens now, each with a sentence explaining what it is for - and a tab has
 * nowhere to put that, while a horizontal strip gives every section added
 * later a smaller share of the same line.
 * ------------------------------------------------------------------------- */

/*
 * The menu sits against the left edge and the screen it belongs to takes the
 * rest. It used to be a 1240px column centred in the window, which on a wide
 * monitor left the same amount of empty space either side of it as the whole
 * template table had to lay itself out in.
 */
.es-adminwrap {
    display: grid;
    grid-template-columns: 250px minmax(0, 1fr);
    gap: 28px;
    padding: 28px 28px 60px;
    align-items: start;
}

.es-adminnav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px;
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-lg);
    /* Follows the screen on the long pages - the AI one runs to several
       thousand words of generations and the way out should not be at the
       bottom of it. */
    position: sticky;
    top: 20px;
}

.es-adminnav__item {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr);
    gap: 2px 10px;
    padding: 9px 10px;
    border-radius: var(--es-radius);
    color: var(--es-text);
    text-decoration: none;
    line-height: 1.35;
}

.es-adminnav__item i {
    grid-row: 1 / span 2;
    align-self: center;
    justify-self: center;
    font-size: 13px;
    color: var(--es-text-muted);
}

.es-adminnav__label { font-size: 13.5px; font-weight: 600; }

.es-adminnav__hint {
    font-size: 11.5px;
    color: var(--es-text-subtle);
}

.es-adminnav__item:hover { background: var(--es-surface-alt); }

.es-adminnav__item.is-active {
    background: var(--es-primary-soft, var(--es-primary-ring));
    color: var(--es-primary-strong, var(--es-primary));
}

.es-adminnav__item.is-active i,
.es-adminnav__item.is-active .es-adminnav__hint { color: inherit; opacity: .85; }

/* The way out is not one of the sections, so it is set apart from them. */
.es-adminnav__item--out {
    margin-top: 6px;
    padding-top: 12px;
    border-top: 1px solid var(--es-border);
    border-radius: 0 0 var(--es-radius) var(--es-radius);
    color: var(--es-text-muted);
}

.es-adminnav__item--out .es-adminnav__label { font-weight: 500; }

/* Narrow screens: the menu becomes a band above the screen it belongs to. */
@media (max-width: 860px) {
    .es-adminwrap { grid-template-columns: minmax(0, 1fr); gap: 18px; }

    .es-adminnav { position: static; flex-direction: row; flex-wrap: wrap; }
    .es-adminnav__item { grid-template-columns: 18px auto; flex: 1 1 auto; }
    .es-adminnav__hint { display: none; }
}

/* The small table showing what a worked example produces. Same markup renders
   on the site's /help/ page, which carries its own copy of this. */
.es-doc-table {
    display: block;
    overflow-x: auto;
    width: 100%;
    margin: 0 0 14px;
    border-collapse: collapse;
    font-size: 13px;
    white-space: nowrap;
}
.es-doc-table th, .es-doc-table td {
    padding: 7px 12px;
    border: 1px solid var(--es-border);
    text-align: left;
}
.es-doc-table th { background: var(--es-surface-alt); font-weight: 600; }
.es-doc-table td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ===========================================================================
   API Connector
   ========================================================================= */

.es-api__list { display: grid; gap: 8px; margin-bottom: 10px; }

.es-api__row {
    display: grid;
    grid-template-columns: 1fr 1fr auto auto;
    gap: 6px;
    align-items: center;
}

.es-api__row--param { grid-template-columns: 1fr auto 1fr auto; }

.es-api__row input,
.es-api__row select {
    width: 100%;
    min-width: 0;
    padding: 7px 9px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    background: var(--es-surface);
    font: inherit;
    font-size: 12.5px;
    color: var(--es-text);
}

.es-api__row input:focus, .es-api__row select:focus {
    outline: 0;
    border-color: var(--es-primary);
}

.es-api__reveal, .es-api__remove {
    border: 1px solid var(--es-border);
    background: var(--es-surface-alt);
    border-radius: var(--es-radius-sm);
    width: 28px;
    height: 30px;
    line-height: 1;
    cursor: pointer;
    color: var(--es-text-muted);
    font-size: 13px;
}

.es-api__remove:hover { border-color: #e0645a; color: #d0453a; }

.es-api__add, .es-api__test {
    border: 1px dashed var(--es-border);
    background: none;
    border-radius: var(--es-radius-sm);
    padding: 8px 12px;
    width: 100%;
    cursor: pointer;
    color: var(--es-primary);
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
}

.es-api__add:hover, .es-api__test:hover {
    border-color: var(--es-primary);
    background: var(--es-primary-soft);
}

.es-api__test { border-style: solid; margin-top: 8px; }

.es-api__chosen { width: 100%; border-collapse: collapse; font-size: 12px; }
.es-api__chosen th {
    text-align: left;
    padding: 5px 8px 5px 0;
    color: var(--es-text-muted);
    font-weight: 600;
    border-bottom: 1px solid var(--es-border);
}
.es-api__chosen td { padding: 5px 8px 5px 0; border-bottom: 1px solid var(--es-border); }
.es-api__chosen code { font-size: 11.5px; word-break: break-all; }
.es-api__chosen input {
    width: 100%;
    padding: 5px 7px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 12px;
}

.es-api__tag {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 10px;
    background: var(--es-primary-soft);
    color: var(--es-primary);
    font-size: 10px;
    font-weight: 700;
}

.es-api__note { margin: 8px 0 0; font-size: 11.5px; color: var(--es-text-muted); }

/* --- the test dialog ---------------------------------------------------- */

/*
 * The allow-list notice. Green rather than a warning colour: it is something
 * to do if calls are refused, not something that has gone wrong.
 */
.es-api-test__allow {
    margin-bottom: 14px;
    padding: 10px 14px;
    background: var(--es-primary-soft);
    border-left: 3px solid var(--es-primary);
    border-radius: var(--es-radius-sm);
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--es-text);
}

.es-api-test__values { margin-bottom: 14px; }
.es-api-test__values h4, .es-api-test__picked h4 {
    margin: 0 0 8px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .6px;
    color: var(--es-text-muted);
}

.es-api-test__value {
    display: grid;
    grid-template-columns: 150px 1fr;
    gap: 8px;
    align-items: center;
    margin-bottom: 6px;
    font-size: 12.5px;
}

.es-api-test__value input {
    padding: 7px 9px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 12.5px;
}

.es-api-test__actions { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }

.es-api-test__run {
    border: 0;
    background: var(--es-primary);
    color: #fff;
    border-radius: var(--es-radius-sm);
    padding: 9px 16px;
    font: inherit;
    font-weight: 600;
    font-size: 12.5px;
    cursor: pointer;
}

.es-api-test__run:disabled { opacity: .6; cursor: default; }

.es-api-test__status { font-size: 12.5px; color: var(--es-text-muted); }
.es-api-test__status.is-ok { color: var(--es-primary); }
.es-api-test__status.is-error { color: #d0453a; }

.es-api-test__search {
    width: 100%;
    padding: 9px 12px;
    margin-bottom: 8px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 12.5px;
}

/*
 * The response, as clickable lines rather than a block of text.
 *
 * It reads the way the JSON does - path on the left, value on the right, in
 * the order the API sent them - but every line can be picked. A <pre> of raw
 * JSON would look more familiar and there would be nothing to click.
 */
.es-api-test__json {
    max-height: 300px;
    overflow: auto;
    margin: 0 0 14px;
    padding: 6px;
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font-size: 12px;
    white-space: pre-wrap;
}

.es-api-test__line {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 24px;
    gap: 10px;
    align-items: baseline;
    width: 100%;
    padding: 5px 8px;
    border: 0;
    border-radius: var(--es-radius-sm);
    background: none;
    text-align: left;
    font: inherit;
    font-size: 12px;
    cursor: pointer;
}

.es-api-test__line:hover { background: var(--es-primary-soft); }
.es-api-test__line.is-picked { opacity: .55; cursor: default; }
.es-api-test__line.is-list .es-api-test__val { color: var(--es-primary); font-weight: 600; }

.es-api-test__path {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    color: var(--es-text);
    word-break: break-all;
}

.es-api-test__val { color: var(--es-text-muted); word-break: break-all; }
.es-api-test__pick { text-align: center; color: var(--es-primary); font-weight: 700; }
.es-api-test__none { padding: 12px; color: var(--es-text-muted); font-size: 12.5px; }

.es-api-test__picked { border-top: 1px solid var(--es-border); padding-top: 12px; }

/* ---------------------------------------------------------------------------
   The response table on a published calculator
   --------------------------------------------------------------------------- */

.calc-api-table { margin: 12px 0; }
.calc-api-table__title { margin: 0 0 8px; font-size: 15px; }

/*
 * Capped and scrolled rather than allowed to run.
 *
 * A rate API answers with a row per karat and a row per unit; printed in full
 * it pushed the result field - the thing the visitor came for - two screens
 * down the page. The heading stays put while the rows move, or nobody can tell
 * which column they are reading by row thirty.
 */
.calc-api-table__body {
    max-height: 500px;
    overflow: auto;
    border: 1px solid rgba(0, 0, 0, .1);
    border-radius: 10px;
}

.calc-api-table table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 14px; }

.calc-api-table th, .calc-api-table td {
    padding: 9px 14px;
    border-bottom: 1px solid rgba(0, 0, 0, .08);
    text-align: left;
}

.calc-api-table td + td, .calc-api-table th + th { border-left: 1px solid rgba(0, 0, 0, .06); }
.calc-api-table tr:last-child td { border-bottom: 0; }

.calc-api-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: #f4f7fa;
    font-weight: 600;

    /*
     * A sticky cell keeps its own border while the rows slide under it, and a
     * collapsed border belongs to the table rather than the cell - which is
     * why the table is separate above and the line is drawn as a shadow here.
     */
    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .12);
}

/* --- the two views of a response ---------------------------------------- */

.es-api-test__tabs {
    display: flex;
    gap: 2px;
    padding: 3px;
    margin-bottom: 10px;
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
}

.es-api-test__tab {
    flex: 1;
    border: 0;
    background: none;
    border-radius: calc(var(--es-radius-sm) - 2px);
    padding: 7px 12px;
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--es-text-muted);
    cursor: pointer;
}

.es-api-test__tab.is-active {
    background: var(--es-surface);
    color: var(--es-text);
    box-shadow: 0 1px 3px rgba(16, 24, 40, .08);
}

.es-api-test__raw {
    max-height: 320px;
    overflow: auto;
    margin: 0 0 14px;
    padding: 12px 14px;
    background: #0f1729;
    border-radius: var(--es-radius-sm);
    color: #c8d3e6;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    line-height: 1.6;
    white-space: pre;
    tab-size: 2;
}

/*
 * A value in the raw JSON is clickable, and has to look it.
 *
 * A dotted underline rather than a button: it must still read as JSON. The
 * tooltip says what clicking does, because "this text is a control" is not
 * something a dotted line can convey on its own.
 */
.es-api-test__raw-value {
    position: relative;
    border-bottom: 1px dotted #6d8cc0;
    color: #7fd8b0;
    cursor: pointer;
    transition: background .12s, color .12s;
}

.es-api-test__raw-value:hover {
    background: rgba(127, 216, 176, .16);
    color: #a8f0ce;
}

.es-api-test__raw-value.is-picked {
    border-bottom-style: solid;
    border-bottom-color: #7fd8b0;
    cursor: default;
    opacity: .65;
}

.es-api-test__raw-value.is-picked:hover { background: none; }

/* The tooltip itself, from the data-tip attribute. */
.es-api-test__raw-value::after {
    content: attr(data-tip);
    position: absolute;
    left: 0;
    bottom: calc(100% + 7px);
    z-index: 5;
    width: max-content;
    max-width: 280px;
    padding: 7px 10px;
    border-radius: 6px;
    background: #1f2a3d;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .35);
    color: #e6edf7;
    font-family: "DM Sans", system-ui, sans-serif;
    font-size: 11.5px;
    line-height: 1.45;
    white-space: normal;
    opacity: 0;
    visibility: hidden;
    transition: opacity .14s;
    pointer-events: none;
}

.es-api-test__raw-value:hover::after { opacity: 1; visibility: visible; }

/*
 * A confirmation for something clicked far from where it lands.
 *
 * The usable-variables table is below the response, and on a long one it is
 * off the bottom of the dialog - so clicking a value in the raw JSON looked
 * like nothing had happened.
 */
.es-api-toast {
    position: fixed;
    left: 50%;
    bottom: 30px;
    z-index: 1000;
    transform: translate(-50%, 14px);
    padding: 11px 18px;
    border-radius: 9px;
    background: #10233a;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .28);
    color: #eaf3ff;
    font-size: 13px;
    opacity: 0;
    transition: opacity .22s, transform .22s;
    pointer-events: none;
}

.es-api-toast.is-in { opacity: 1; transform: translate(-50%, 0); }

.calc-api-table__empty { margin: 0; color: #7a8494; font-size: 14px; }


/* ---------------------------------------------------------------------------
   The chosen-values list in the settings panel
   --------------------------------------------------------------------------- */

/*
 * Twenty values chosen from a rate API is twenty rows, and the panel is a
 * column six hundred pixels tall - so everything below this setting was pushed
 * out of reach. The list scrolls inside itself and the heading stays with it.
 */
.es-api__chosen-wrap {
    max-height: 260px;
    overflow: auto;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
}

.es-api__chosen { margin: 0; }

.es-api__chosen thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--es-surface-alt);
    padding: 7px 8px;
    box-shadow: inset 0 -1px 0 var(--es-border);
    border-bottom: 0;
}

.es-api__chosen td { padding: 6px 8px; }
.es-api__chosen tr:last-child td { border-bottom: 0; }

.es-api__count {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin: 0 0 6px;
    font-size: 11.5px;
    color: var(--es-text-muted);
}

/*
 * "This is your last response" - shown when the dialog opens with something
 * remembered rather than something just fetched.
 *
 * Amber rather than green: the figures are real but they are not current, and
 * somebody choosing values off yesterday's prices should notice.
 */
.es-api-test__stale {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    margin-bottom: 10px;
    padding: 10px 14px;
    background: #fff8e8;
    border-left: 3px solid #e8a33d;
    border-radius: var(--es-radius-sm);
    font-size: 12.5px;
    line-height: 1.5;
    color: #3d3320;
}

.es-api-test__stale button {
    flex: 0 0 auto;
    border: 1px solid #e0b978;
    background: #fff;
    border-radius: var(--es-radius-sm);
    padding: 7px 12px;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    color: #7a5a17;
    cursor: pointer;
    white-space: nowrap;
}

.es-api-test__stale button:hover { background: #fdf1d9; border-color: #c99a4e; }

/* --- datasets in the test dialog ---------------------------------------- */

.es-api-sets { display: grid; gap: 8px; margin-bottom: 16px; }

.es-api-sets__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 10px;
    align-items: center;
    padding: 11px 13px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    background: var(--es-surface);
}

.es-api-sets__row.is-used { opacity: .6; }

.es-api-sets__what { min-width: 0; }
.es-api-sets__what code { font-size: 12px; word-break: break-all; }

.es-api-sets__what input {
    width: 100%;
    padding: 6px 8px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 12.5px;
}

.es-api-sets__size {
    display: block;
    margin-top: 3px;
    font-size: 11.5px;
    color: var(--es-text-muted);
}

/*
 * The length warning. Nothing in JSON says series_1[2] belongs beside
 * x_axis[2] - the lengths can be checked and the alignment cannot, so this
 * says what is known rather than implying the rest was verified.
 */
.es-api-sets__warn {
    grid-column: 1 / -1;
    margin: 6px 0 0;
    padding: 7px 10px;
    background: #fff8e8;
    border-left: 3px solid #e8a33d;
    border-radius: var(--es-radius-sm);
    font-size: 11.5px;
    line-height: 1.5;
    color: #3d3320;
}

.es-api-sets__row > button {
    flex: 0 0 auto;
    border: 1px solid var(--es-primary);
    background: var(--es-primary-soft);
    color: var(--es-primary);
    border-radius: var(--es-radius-sm);
    padding: 7px 13px;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}

.es-api-sets__row > button:hover:not(:disabled) { background: var(--es-primary); color: #fff; }
.es-api-sets__row > button:disabled { border-color: var(--es-border); background: none;
    color: var(--es-text-muted); cursor: default; }

.es-api .es-api__list > select {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 12.5px;
}

/* The column picker on a chart reading an API dataset. */
.es-api__sub {
    display: block;
    margin: 10px 0 5px;
    font-size: 11.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--es-text-muted);
}

.es-api__sub:first-child { margin-top: 0; }



/* A chosen value the current response no longer carries. */
.es-api__chosen tr.is-missing td { background: #fff6f5; color: #97362d; }
.es-api__chosen tr.is-missing code { text-decoration: line-through; opacity: .75; }

/* Naming a dataset's columns for the legend and the table heading. */
.es-api-sets__titles {
    grid-column: 1 / -1;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--es-border);
    display: grid;
    gap: 6px;
}

.es-api-sets__title {
    display: grid;
    grid-template-columns: minmax(0, 140px) minmax(0, 1fr);
    gap: 10px;
    align-items: center;
}

.es-api-sets__title code {
    font-size: 11.5px;
    color: var(--es-text-muted);
    word-break: break-all;
}

.es-api-sets__title input {
    padding: 6px 9px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 12.5px;
}

/* --- a dial's configuration ---------------------------------------------- */

.es-dial__cell {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 12.5px;
}

.es-dial > select {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 12.5px;
}

.es-dial__bands { display: grid; gap: 7px; margin-bottom: 8px; }

.es-dial__band {
    display: grid;
    grid-template-columns: 38px minmax(0, 1fr) minmax(0, 1fr) auto;
    gap: 7px;
    align-items: center;
}

.es-dial__band input[type="color"] {
    width: 38px;
    height: 32px;
    padding: 2px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    background: none;
    cursor: pointer;
}

.es-dial__band input[type="number"] {
    width: 100%;
    min-width: 0;
    padding: 7px 9px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 12.5px;
}

/* ---------------------------------------------------------------------------
   Admin > Template categories
   ---------------------------------------------------------------------------
   Each main category is a card; its sub-categories are rows inside it. Every
   row is its own form - renaming, reordering and deleting all post - so the
   layout is done on the forms rather than around them.
   --------------------------------------------------------------------------- */

.es-cat-add {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
}

.es-cat-add textarea,
.es-cat-add select {
    padding: 8px 11px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 14px;
}

/*
 * The box takes a list now, one name per line.
 *
 * align-items on the row is centre, which is right for a control one line
 * high and wrong for one three lines high - the dropdown and the button would
 * float at its middle. These two sit at the top of the row instead, level with
 * the first line somebody types.
 */
.es-cat-add { align-items: flex-start; }

.es-cat-add textarea {
    flex: 1 1 260px;
    min-height: 76px;
    line-height: 1.55;
    resize: vertical;
}

/* Back on the line the dropdown is on, which is the row's own height. */
.es-cat-add select,
.es-cat-add .es-btn { margin-top: 0; }

/*
 * .es-card carries no padding of its own - it expects __header and __body, and
 * these screens went out without them, so every field sat flush against the
 * border and the cards ran into each other as one long box. The markup uses
 * the house pattern now; what is left here is the spacing between them.
 */
.es-cat { margin-bottom: 20px; }

/* The rename form and the reordering buttons, in the card's header row. */
.es-cat__head { flex-wrap: wrap; }

.es-cat__rename {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.es-cat__rename input[type="text"] {
    padding: 7px 10px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    min-width: 200px;
}

/* The address. Shown next to the name because it is what the site's links are
   made of and, unlike the name, it never changes once the category exists. */
.es-cat__rename code {
    padding: 3px 7px;
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font-size: 12px;
    color: var(--es-text-subtle);
}

.es-cat__rename small {
    font-size: 12px;
    color: var(--es-text-subtle);
}

.es-cat__tools {
    display: flex;
    gap: 6px;
    align-items: center;
}

.es-cat__tools form { margin: 0; }

.es-cat__count { margin: 0; }

.es-cat__subs {
    margin: 14px 0 0;
    padding: 14px 0 0;
    list-style: none;
    border-top: 1px solid var(--es-border);
}

.es-cat__subs li {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    justify-content: space-between;
    padding: 10px 0 10px 22px;
    border-bottom: 1px solid var(--es-border);
    position: relative;
}

/* A tick of a line, so a sub-category reads as sitting inside the card rather
   than as another category that happens to be printed lower down. */
.es-cat__subs li::before {
    content: "";
    position: absolute;
    left: 6px;
    top: 50%;
    width: 9px;
    height: 1px;
    background: var(--es-border);
}

.es-cat__subs li:last-child { border-bottom: 0; }

.es-cat__subs form { margin: 0; }

/* ---------------------------------------------------------------------------
   Admin > Docs examples
   ---------------------------------------------------------------------------
   The documentation on the left, one topic's examples on the right. Two panes
   rather than one long page: there are fifty-seven places an example can go,
   and scrolling past all of them to reach the one being worked on is the whole
   problem the split solves.
   --------------------------------------------------------------------------- */

.es-docex {
    display: grid;
    grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
    gap: 16px;
    align-items: start;
}

/*
 * The documentation is fifty-seven places long. It scrolls inside its own card
 * so that choosing a topic does not mean scrolling the page past all of them,
 * and so the pane on the right stays where it was put.
 */
.es-docex__list ul {
    margin: 12px -8px 0;
    padding: 0 8px;
    list-style: none;
    max-height: 560px;
    overflow-y: auto;
}

.es-docex__list li a {
    display: flex;
    gap: 8px;
    align-items: center;
    justify-content: space-between;
    padding: 7px 10px;
    border-radius: var(--es-radius-sm);
    color: var(--es-text);
    font-size: 13.5px;
    text-decoration: none;
}

.es-docex__list li a:hover {
    background: var(--es-surface-alt);
    text-decoration: none;
}

.es-docex__list li.is-topic a {
    font-weight: 700;
    margin-top: 8px;
}

.es-docex__list li.is-section a {
    padding-left: 22px;
    color: var(--es-text-subtle);
}

.es-docex__list li.is-active a {
    background: var(--es-primary);
    color: #fff;
}

/* The count of what is already attached. Only printed when there is one, so
   the list is not a column of noughts. */
.es-docex__list li b {
    min-width: 20px;
    padding: 1px 6px;
    background: var(--es-surface-alt);
    border-radius: 999px;
    font-size: 11.5px;
    text-align: center;
}

.es-docex__list li.is-active b { background: rgba(255, 255, 255, .25); }

.es-docex__add {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    margin: 16px 0 18px;
    padding-bottom: 18px;
    border-bottom: 1px solid var(--es-border);
}

.es-docex__add select {
    flex: 1 1 320px;
    padding: 8px 11px;
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius-sm);
    font: inherit;
    font-size: 14px;
}

.es-docex__detail > .es-card__body > .es-help:first-child { margin-top: 0; }

/*
 * This one lives inside the card body, under the form that adds a row, so it
 * lines up with that rather than going flush to the card edges the way the
 * library table does.
 */
.es-docex__table { width: 100%; }

.es-docex__table th:first-child,
.es-docex__table td:first-child { padding-left: 0; }

.es-docex__table th:last-child,
.es-docex__table td:last-child { padding-right: 0; text-align: right; }

.es-docex__table form { margin: 0; }

.es-docex__table td { vertical-align: middle; }

@media (max-width: 900px) {
    .es-docex { grid-template-columns: minmax(0, 1fr); }
    .es-docex__list ul { max-height: 320px; }
}

/* Attached but not published, so not on the site yet. */
.es-docex__draft {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 7px;
    background: #fff4e0;
    border: 1px solid #f0d3a3;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
    color: #8a5b12;
}

/* ---------------------------------------------------------------------------
   Two-column form
   ---------------------------------------------------------------------------
   A template has ten fields, each of which was a full-width box on its own
   row: the form ran well past the fold and the SEO fields - the ones most
   often left empty - were the ones you had to scroll to find. The pairs sit
   side by side; anything that holds a sentence spans both.
   --------------------------------------------------------------------------- */

.es-form-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 22px;
}

.es-form-grid > .es-field--wide { grid-column: 1 / -1; }

.es-form-grid label {
    display: block;
    margin-bottom: 6px;
    font-size: 13px;
    font-weight: 580;
    color: var(--es-text);
}

.es-form-grid textarea.es-input {
    resize: vertical;
    line-height: 1.5;
}

/* How much has been written, against how much of it gets shown. Sits at the
   right-hand end of the label, where it is next to the box it counts. */
.es-count {
    float: right;
    font-size: 12px;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    color: var(--es-text-subtle);
    cursor: default;
}

.es-count.is-warn { color: #b5710a; }

@media (max-width: 760px) {
    .es-form-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ===========================================================================
   Components the admin screens borrowed from the builder
   ---------------------------------------------------------------------------
   The AI settings screen draws a toggle switch and the domain settings screen
   shows the generated rewrite rules in a <pre>. Both were written with classes
   that live in builder.css, which no admin screen loads - so the switch
   rendered as a bare checkbox and the rules block as unstyled text.

   Copied here rather than linking builder.css into the admin, which would pull
   a canvas stylesheet into a settings page for the sake of thirty lines. If
   these two ever need to agree with the builder's versions, this is the note
   that says there are two.
   ========================================================================= */

.es-switch { position: relative; width: 38px; height: 22px; flex: 0 0 38px; }

.es-switch input {
    position: absolute;
    opacity: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
}

.es-switch__track {
    position: absolute;
    inset: 0;
    background: var(--es-border-strong);
    border-radius: 999px;
    transition: background-color .15s ease;
    /* The input above is what receives the click; the track only draws. */
    pointer-events: none;
}

.es-switch__track::after {
    content: '';
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    background: #fff;
    border-radius: 50%;
    box-shadow: var(--es-shadow-xs);
    transition: transform .15s ease;
}

.es-switch input:checked + .es-switch__track { background: var(--es-primary); }
.es-switch input:checked + .es-switch__track::after { transform: translateX(16px); }
.es-switch input:focus-visible + .es-switch__track { box-shadow: 0 0 0 3px var(--es-primary-ring); }

/* A label with a switch at one end of it. */
.es-set-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    cursor: pointer;
}

/* Generated output shown back to whoever generated it - the rewrite rules on
   the domain settings screen. Monospaced, scrollable, and not editable. */
.es-pre {
    margin: 0;
    padding: 13px 15px;
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius);
    font-family: var(--es-font-mono);
    font-size: 12px;
    line-height: 1.6;
    color: var(--es-text-muted);
    white-space: pre;
    overflow: auto;
}


/* Admin template library: search and bulk selection ------------------------
   A heading with a control beside it, and the search box that sits there.
   ------------------------------------------------------------------------- */

.es-card__header--split {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

/*
 * The search and sort controls carry .es-input and .es-select, so they are
 * already the right height and border - all that is left is how much room
 * each of them takes.
 */
.es-tpl-search { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Wide enough for a template title, which is what is usually pasted in. */
.es-tpl-search .es-input { width: 250px; max-width: 100%; }
/*
 * Capped, because the longest sub-category - "Marketing, Agencies and Web Dev"
 * - would otherwise set the width of the control and push the buttons onto a
 * line of their own.
 */
.es-tpl-search .es-select { width: auto; max-width: 210px; }

@media (max-width: 720px) {
    .es-tpl-search { width: 100%; }
    .es-tpl-search .es-input { flex: 1 1 160px; width: auto; }
    .es-tpl-search .es-select { flex: 1 1 160px; }
}


/* A screenshot run in progress -------------------------------------------- */

.es-shots-wait { display: inline-flex; align-items: center; gap: 5px; }

.es-shots-wait i {
    font-size: 10px;
    animation: es-spin 1.4s linear infinite;
}

@keyframes es-spin { to { transform: rotate(360deg); } }

/* Somebody who has asked not to see movement still needs to know it is
   working - the badge and its wording say so without the turning. */
@media (prefers-reduced-motion: reduce) {
    .es-shots-wait i { animation: none; }
}


/* Filtering a list in the browser ------------------------------------------ */

.es-listfilter {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}

/* Wide enough for a calculator name, which is what gets typed here. */
.es-listfilter .es-input { width: 280px; max-width: 100%; }

.es-listfilter__count { font-size: 13px; color: var(--es-text-muted); }
.es-listfilter__count[hidden] { display: none; }

@media (max-width: 640px) {
    .es-listfilter .es-input { flex: 1; width: auto; }
}

/* ---------------------------------------------------------------------------
   Templates: the library and the import form, as two tabs

   Importing is an occasional errand and the library is what the screen is for,
   so the form no longer sits above the list pushing it off the screen.
   --------------------------------------------------------------------------- */

.es-tpl-tabs {
    display: flex;
    gap: 4px;
    margin: -6px 0 18px;
    border-bottom: 1px solid var(--es-border);
}

.es-tpl-tab {
    display: inline-block;
    padding: 9px 16px;
    margin-bottom: -1px;
    border-bottom: 2px solid transparent;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--es-muted);
    text-decoration: none;
}

.es-tpl-tab:hover { color: var(--es-text); }

.es-tpl-tab.is-active {
    color: var(--es-primary);
    border-bottom-color: var(--es-primary);
}

/* ---------------------------------------------------------------------------
   The row menu on My Calculators

   Five buttons on every row is a wall of them - eighty calculators put four
   hundred controls on the screen, and Delete sits a few pixels from Edit on
   every one. One button, and the choices behind it.
   --------------------------------------------------------------------------- */

.es-rowmenu { position: relative; display: inline-block; }

.es-rowmenu__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--es-radius-sm);
    background: none;
    color: var(--es-muted);
    cursor: pointer;
}

.es-rowmenu__toggle svg { width: 18px; height: 18px; }

.es-rowmenu__toggle:hover,
.es-rowmenu__toggle[aria-expanded="true"] {
    background: var(--es-surface-alt);
    border-color: var(--es-border);
    color: var(--es-text);
}

.es-rowmenu__panel {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    z-index: 40;
    min-width: 210px;
    padding: 6px;
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius);
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.16);
    text-align: left;
}

/* Opened upwards when the row is near the bottom of the window - a menu
   dropped from the last row is a menu mostly below the fold. */
.es-rowmenu.is-up .es-rowmenu__panel { top: auto; bottom: calc(100% + 6px); }

.es-rowmenu__item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 10px;
    border: 0;
    border-radius: var(--es-radius-sm);
    background: none;
    font: inherit;
    font-size: 13.5px;
    color: var(--es-text);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.es-rowmenu__item svg { width: 16px; height: 16px; flex: 0 0 auto; color: var(--es-muted); }
.es-rowmenu__item:hover { background: var(--es-surface-alt); }

.es-rowmenu__item--danger { color: var(--es-danger, #b91c1c); }
.es-rowmenu__item--danger svg { color: currentColor; }
.es-rowmenu__item--danger:hover { background: var(--es-danger-soft, #fef2f2); }

.es-rowmenu__rule {
    height: 1px;
    margin: 6px 4px;
    background: var(--es-border);
}

/* ---------------------------------------------------------------------------
   Create: the way through to the template library

   The library lives on the site, where every entry has a preview and a
   description. This page points at it rather than keeping a second, smaller
   copy that was always the one behind.
   --------------------------------------------------------------------------- */

.es-startfrom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
    margin-top: 22px;
    padding: 22px 24px;
    background: var(--es-surface);
    border: 1px solid var(--es-border);
    border-radius: var(--es-radius);
}

.es-startfrom__body { flex: 1 1 320px; min-width: 0; }
.es-startfrom__body h2 { margin: 0 0 6px; font-size: 17px; }

.es-startfrom__body p {
    margin: 0;
    max-width: 62ch;
    color: var(--es-muted);
    font-size: 13.5px;
    line-height: 1.55;
}

.es-startfrom .es-btn { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 8px; }
.es-startfrom .es-btn svg { width: 15px; height: 15px; }

/* ---------------------------------------------------------------------------
 * Connecting a WordPress site.
 *
 * One card on an empty page - wp-connect/authorize.php is reached from another
 * website and leads nowhere in this app, so the navigation would only offer
 * ways to abandon what the visitor came to do.
 * ------------------------------------------------------------------------ */

.es-wpauth-body {
    margin: 0;
    background: var(--es-surface-alt, #f6f8fa);
    color: var(--es-text, #1f2937);
    font-family: var(--es-font, system-ui, -apple-system, "Segoe UI", sans-serif);
}

.es-wpauth {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    min-height: 100vh;
    padding: 48px 20px;
    box-sizing: border-box;
}

.es-wpauth__card {
    width: 100%;
    max-width: 520px;
    padding: 32px;
    box-sizing: border-box;
    background: var(--es-surface, #fff);
    border: 1px solid var(--es-border, #e5e7eb);
    border-radius: var(--es-radius, 12px);
    box-shadow: var(--es-shadow-sm, 0 1px 3px rgba(0, 0, 0, .06));
}

.es-wpauth__brand { margin-bottom: 24px; }

.es-wpauth__title {
    margin: 0 0 12px;
    font-size: 22px;
    line-height: 1.3;
}

.es-wpauth__lead {
    margin: 0 0 16px;
    font-size: 14px;
    line-height: 1.6;
    color: var(--es-text, #1f2937);
}

/*
 * What is being connected to what, as a pair of facts rather than a sentence.
 * The account line is the one that matters: somebody signed into the wrong
 * account has no other way to notice before they say yes.
 */
.es-wpauth__facts {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 8px 16px;
    margin: 0 0 20px;
    padding: 16px;
    background: var(--es-surface-alt, #f6f8fa);
    border-radius: var(--es-radius-sm, 8px);
    font-size: 13px;
}

.es-wpauth__facts dt { color: var(--es-text-muted, #6b7280); }

.es-wpauth__facts dd {
    margin: 0;
    font-weight: 600;
    word-break: break-all;
}

.es-wpauth__list {
    margin: 0 0 16px;
    padding-left: 20px;
    font-size: 14px;
    line-height: 1.9;
}

.es-wpauth__note {
    margin: 0 0 24px;
    font-size: 13px;
    line-height: 1.6;
    color: var(--es-text-muted, #6b7280);
}

.es-wpauth__notice,
.es-wpauth__error {
    margin: 0 0 20px;
    padding: 12px 14px;
    border-radius: var(--es-radius-sm, 8px);
    font-size: 13px;
    line-height: 1.5;
}

.es-wpauth__notice {
    background: var(--es-warn-soft, #fff7ed);
    border: 1px solid var(--es-warn-border, #fed7aa);
    color: var(--es-warn-strong, #9a3412);
}

.es-wpauth__error {
    background: var(--es-danger-soft, #fef2f2);
    border: 1px solid var(--es-danger-border, #fecaca);
    color: var(--es-danger-strong, #991b1b);
}

.es-wpauth__actions {
    display: flex;
    gap: 10px;
    align-items: center;
}

@media (max-width: 480px) {
    .es-wpauth { padding: 20px 12px; }
    .es-wpauth__card { padding: 22px; }
    .es-wpauth__actions { flex-direction: column; align-items: stretch; }
}

/* ---------------------------------------------------------------------------
 * My Forms & Calculators - one list, two shapes
 *
 * The rows are the same markup either way; a class on the container decides
 * whether each one lays out as a line in a table or as a card in a grid. That
 * is what lets renaming, deleting, filtering and selecting keep working in
 * both without a second copy of anything to keep in step.
 * ------------------------------------------------------------------------ */

/* The toggle sits at the end of the filter bar. */
.es-listfilter .es-layouts { margin-left: auto; }

.es-layouts {
    display: inline-flex;
    padding: 3px;
    background: var(--es-surface-alt, #f6f8fa);
    border: 1px solid var(--es-border, #e5e7eb);
    border-radius: var(--es-radius-sm, 8px);
}

.es-layouts__btn {
    display: grid;
    place-items: center;
    width: 36px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--es-text-muted, #6b7280);
    cursor: pointer;
    transition: background-color .12s ease, color .12s ease;
}

.es-layouts__btn:hover { color: var(--es-text, #1f2937); }

.es-layouts__btn.is-on {
    background: #fff;
    color: var(--es-primary, #00a862);
    box-shadow: var(--es-shadow-xs, 0 1px 2px rgba(16, 24, 40, .08));
}

.es-calclist {
    background: #fff;
    border: 1px solid var(--es-border, #e5e7eb);
    border-radius: var(--es-radius, 12px);
    box-shadow: var(--es-shadow-sm, 0 1px 3px rgba(16, 24, 40, .06));
    /*
     * NOT overflow: hidden.
     *
     * It was there to clip the rows to the rounded corners, and it clipped the
     * row menu with them. With several rows the menu opened inside the box and
     * looked fine; with ONE row the box is barely taller than the button, so
     * the panel fell outside it and all that showed was the sliver that
     * happened to overlap - an empty white rectangle under the dots.
     *
     * Opening it upwards would not have helped: a box that short clips the
     * panel whichever way it goes.
     *
     * The corners are rounded on the rows themselves instead, which is the
     * same picture and does not decide what may leave the box.
     */
    overflow: visible;
}

.es-calclist--list .es-calclist__head {
    border-radius: var(--es-radius, 12px) var(--es-radius, 12px) 0 0;
}

.es-calclist--list .es-calcrow:last-child {
    border-radius: 0 0 var(--es-radius, 12px) var(--es-radius, 12px);
}

/*
 * The columns, declared once and shared by the heading row and every row under
 * it. Two grids that have to line up and are described in two places drift the
 * first time somebody edits one of them.
 */
.es-calclist__head,
.es-calclist--list .es-calcrow {
    display: grid;
    grid-template-columns: 42px minmax(180px, 2.2fr) minmax(120px, 1fr) 110px 150px 52px;
    gap: 12px;
    align-items: center;
}

.es-calclist__head {
    padding: 11px 22px;
    border-bottom: 1px solid var(--es-border, #e5e7eb);
    background: var(--es-surface-alt, #f9fafb);
    font-size: 11.5px;
    font-weight: 620;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--es-text-muted, #6b7280);
}

.es-calclist--list .es-calcrow {
    padding: 14px 22px;
    border-bottom: 1px solid #eef1f4;
}

.es-calclist--list .es-calcrow:last-child { border-bottom: 0; }
.es-calclist--list .es-calcrow:hover { background: #fbfcfd; }
.es-calcrow.is-picked { background: var(--es-primary-soft, #ecfdf5); }

.es-calcrow__name { min-width: 0; }
.es-calcrow__actions { display: flex; justify-content: flex-end; }

/* ---------------------------------------------------------------------------
 * The cards
 *
 * The container stops being a panel and becomes a grid of them, so the border
 * and shadow move from the list to each card.
 * ------------------------------------------------------------------------ */

.es-calclist--grid {
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
}

/* ---------------------------------------------------------------------------
   The picture on a card
   ---------------------------------------------------------------------------
   Photographed in the owner browser when they save - see card-shot.js - or, for
   a calculator that has none yet, drawn from its own layout by
   calc_card_wireframe(). The list layout has no room for either, so it hides
   them rather than carrying a second set of markup.
   --------------------------------------------------------------------------- */

.es-calcrow .es-cardshot { display: none; }

.es-calclist--grid .es-cardshot {
    grid-area: shot;
    display: block;
    margin: -14px -14px 3px;
    height: 118px;
    overflow: hidden;
    background: #fbfcfe;
    border-bottom: 1px solid #eef1f4;
    border-radius: var(--es-radius, 12px) var(--es-radius, 12px) 0 0;
}

.es-calclist--grid .es-cardshot img,
.es-calclist--grid .es-cardshot svg {
    display: block;
    width: 100%;
    height: auto;
}

/* The top of the calculator, not the middle of it: the heading and the first
   questions are what make one card recognisable from another. */
.es-calclist--grid .es-cardshot img { object-fit: cover; object-position: top center; }

/* The pinned controls sit on the picture, so they are given something to be
   read against. */
.es-calclist--grid .es-calcrow__pick,
.es-calclist--grid .es-calcrow__actions {
    background: rgba(255, 255, 255, .86);
    border-radius: 6px;
}

.es-calclist--grid .es-calcrow__pick { padding: 2px 4px; }

/* A card carries its own labels, so the column headings have nothing to say. */
.es-calclist--grid .es-calclist__head { display: none; }

.es-calclist--grid #es-calc-rows {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
    gap: 16px;
}

/*
 * A grid rather than a column, so the status and the counts - two short things
 * that were each taking a line of their own - sit side by side. Four stacked
 * rows of text under a picture made every card taller than it had anything to
 * say.
 */
.es-calclist--grid .es-calcrow {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
        "shot   shot"
        "name   name"
        "status meta"
        "date   date";
    /* The last row takes what is left, so the date sits on the card's bottom
       edge and every card in a row lines its date up with the others. Packed
       to the top instead, a short card left the gap UNDER the date, which
       reads as a card that has lost something. */
    grid-template-rows: auto auto auto 1fr;
    gap: 7px 10px;
    padding: 14px 14px 12px;
    background: #fff;
    border: 1px solid var(--es-border, #e5e7eb);
    border-radius: var(--es-radius, 12px);
    box-shadow: var(--es-shadow-sm, 0 1px 3px rgba(16, 24, 40, .06));
    transition: box-shadow .15s ease, transform .15s ease;
}

.es-calclist--grid .es-calcrow:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 10px rgba(16, 24, 40, .07), 0 12px 24px rgba(16, 24, 40, .07);
}

/*
 * The checkbox and the menu are pinned to the corners, so the card's own
 * content starts below them and the name is never pushed sideways by either.
 */
.es-calclist--grid .es-calcrow__pick {
    position: absolute;
    top: 10px;
    left: 10px;
}

.es-calclist--grid .es-calcrow__actions {
    position: absolute;
    top: 8px;
    right: 8px;
}

/*
 * Two lines, and the rest is an ellipsis.
 *
 * A long name ran to three or four lines, and because every card in a row is
 * the height of the tallest, ONE long name made a whole row of cards tall. Two
 * lines is enough to tell one calculator from another, and the full name is on
 * the card's own page.
 *
 * No side padding either: it was there to clear the checkbox and the menu, and
 * those sit on the picture now - so the name was being squeezed into two
 * thirds of the width for no remaining reason, which is what pushed it onto a
 * third line in the first place.
 */
.es-calclist--grid .es-calcrow__name {
    grid-area: name;
    min-width: 0;
    padding: 0;
    font-size: 15px;
}

.es-calclist--grid .es-calcrow__name .es-table__name {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    line-height: 1.35;
}

/* And the description under it, where there is one, gets a single line. */
.es-calclist--grid .es-calcrow__name .es-muted {
    display: -webkit-box;
    -webkit-line-clamp: 1;
    line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.es-calclist--grid .es-calcrow__status { grid-area: status; }

/* Beside the badge rather than under it, and quiet - it is the smallest thing
   on the card and was taking a whole line. */
.es-calclist--grid .es-calcrow__contents {
    grid-area: meta;
    align-self: center;
    font-size: 12.5px;
    text-align: right;
}

.es-calclist--grid .es-calcrow__updated {
    grid-area: date;
    align-self: end;
    margin-top: 4px;
    padding-top: 8px;
    border-top: 1px solid #eef1f4;
    font-size: 12px;
}

/*
 * A menu opening from a card near the right edge would otherwise run off it.
 * The panel is anchored to its right instead, which is where there is room.
 */
.es-calclist--grid .es-rowmenu__panel { right: 0; left: auto; }

/*
 * And the card it belongs to is lifted while it is open.
 *
 * Every card is position:relative, which makes each one its own stacking
 * context - so a menu hanging below its card was painted UNDER the cards that
 * come after it, and its last items vanished behind the next row. A z-index on
 * the panel cannot fix that: it is trapped inside its own card's context. The
 * card has to rise instead.
 *
 * It applies to the list layout too, where rows overlap the same way.
 */
.es-calcrow.is-menu-open { z-index: 30; }
.es-calclist--list .es-calcrow { position: relative; }

@media (max-width: 900px) {
    .es-calclist__head { display: none; }

    .es-calclist--list .es-calcrow {
        grid-template-columns: 42px 1fr 52px;
        row-gap: 6px;
    }

    .es-calclist--list .es-calcrow__contents,
    .es-calclist--list .es-calcrow__status,
    .es-calclist--list .es-calcrow__updated {
        grid-column: 2 / 3;
    }
}

/* ---------------------------------------------------------------------------
 * A lead, in a panel of its own
 *
 * The detail used to unfold as a second table row, which pushed the rest of
 * the list down the screen - reading one lead moved the next one out from
 * under the pointer. Over the list instead, so closing leaves it exactly where
 * it was.
 * ------------------------------------------------------------------------ */

.es-leadbox {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: grid;
    place-items: center;
    padding: 24px;
}

.es-leadbox[hidden] { display: none; }

.es-leadbox__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(16, 24, 40, .5);
}

.es-leadbox__panel {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 720px;
    max-height: 86vh;
    background: #fff;
    border-radius: var(--es-radius, 12px);
    box-shadow: 0 20px 48px rgba(16, 24, 40, .24);
}

.es-leadbox__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 18px 22px;
    border-bottom: 1px solid var(--es-border, #e5e7eb);
}

.es-leadbox__title {
    margin: 0;
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -.01em;
}

.es-leadbox__x {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--es-text-muted, #6b7280);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
}

.es-leadbox__x:hover { background: var(--es-surface-alt, #f6f8fa); }

/* The body scrolls, not the page behind it. */
.es-leadbox__body {
    padding: 22px;
    overflow-y: auto;
}

/*
 * The detail was built to sit in a table cell the width of the page. In a
 * panel it has half that, so the two columns become one when there is not room
 * for both.
 */
.es-leadbox__body .es-lead-detail__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 24px;
}

/* The list behind a dialog does not scroll. */
body.es-noscroll { overflow: hidden; }

@media (max-width: 600px) {
    .es-leadbox { padding: 12px; }
    .es-leadbox__panel { max-height: 92vh; }
    .es-leadbox__body { padding: 16px; }
}

/* ---------------------------------------------------------------------------
 * The AI conversation, in the same overlay the single exchange uses.
 *
 * One build reads as a fragment: "I could not set the formula for total_value"
 * says nothing about the two prompts that led there. This is the shape of the
 * exchange - what was asked, what came back, what was applied and where it
 * broke - with the raw bytes of any one turn still a click away.
 * ------------------------------------------------------------------------- */

.es-chat__turn {
    border-bottom: 1px solid var(--es-border);
    padding: 0 0 16px;
    margin: 0 0 16px;
}

.es-chat__turn:last-child { border-bottom: 0; margin-bottom: 0; }

.es-chat__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    align-items: center;
    font-size: 11.5px;
    color: var(--es-text-subtle);
    margin: 0 0 8px;
}

/* The prompt sits right, the way the owner saw it in the builder. */
.es-chat__said {
    max-width: 78%;
    margin: 0 0 10px auto;
    padding: 9px 12px;
    border-radius: 10px 10px 2px 10px;
    background: var(--es-primary, #128a4d);
    color: #fff;
    font-size: 13px;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: break-word;
}

.es-chat__answered {
    max-width: 88%;
    padding: 9px 12px;
    border-radius: 10px 10px 10px 2px;
    background: var(--es-surface-alt);
    border: 1px solid var(--es-border);
    font-size: 13px;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: break-word;
}

.es-chat__answered--quiet { color: var(--es-text-subtle); font-style: italic; }

.es-chat__fault {
    margin: 8px 0 0;
    padding: 9px 12px;
    border-radius: 6px;
    background: #fdf2f2;
    border: 1px solid #f3c9c9;
    color: #8c1c1c;
    font-size: 12.5px;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: break-word;
}

/*
 * The operations, as a numbered list rather than a JSON blob. The order is
 * the whole point - a formula set before the field it reads is the commonest
 * way one of these goes wrong - so it is numbered and read top to bottom.
 */
.es-chat__steps {
    margin: 10px 0 0;
    padding: 0 0 0 22px;
    font-size: 12px;
    line-height: 1.6;
    color: var(--es-text);
    max-height: 260px;
    overflow-y: auto;
}

.es-chat__steps li { margin: 0 0 1px; }

.es-chat__more {
    margin-top: 10px;
    display: flex;
    gap: 8px;
    align-items: center;
}

.es-chat__tag {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .01em;
}

.es-chat__tag--ok     { background: #e6f6ec; color: #14683c; }
.es-chat__tag--bad    { background: #fdecec; color: #9b1c1c; }
.es-chat__tag--quiet  { background: var(--es-surface-alt); color: var(--es-text-subtle); }
