/*
 * ai-logline.css
 *
 * The AI logline panel on the script summary card.
 *
 * Deliberately small. The button is .btn .btn-outline from global.css and the
 * heading is .script-section-label from dashboard.css, so nothing here restyles
 * a control that already has a style -- these rules only lay the panel out and
 * dress the result list, using the same variables as the card around it.
 *
 * Namespaced .ai- throughout, like .sb- and .sc- before it, so it can be loaded
 * on any dashboard page without reaching into anything else.
 */

.ai-logline-panel {
    margin-bottom: 14px;
}

.ai-logline-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

/* The result list -------------------------------------------------------- */

.ai-logline-result {
    margin-top: 12px;
}

.ai-logline-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.ai-logline-item {
    border: 1px solid var(--border);
    border-radius: 6px;
    background: #fff;
    padding: 12px 14px;
}

/* The angle -- Classic, Hook-forward, Marketable. Same treatment as the other
   small labels on this card, so the three options read as a set. */
.ai-logline-angle {
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-blue);
    margin-bottom: 4px;
}

.ai-logline-text {
    font-size: 18px;
    line-height: 1.35;
    color: var(--text-soft);
}

.ai-logline-foot {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 8px;
}

.ai-logline-foot .ai-wordcount {
    font-size: 13px;
    color: var(--text-muted);
}

/* The two buttons inside a result. Quieter than .btn: they sit inside a card
   that already has a primary action at the top of it. */
.ai-logline-foot button {
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 600;
    padding: 4px 12px;
    border-radius: 5px;
    border: 1px solid var(--border);
    background: var(--bg-light);
    color: var(--text-soft);
    cursor: pointer;
    transition: all 0.2s;
}

.ai-logline-foot button:hover {
    border-color: var(--primary);
    color: var(--primary);
}

/* Why this version says what it says. Set back and smaller: it is the reasoning
   behind the option, not the option. */
.ai-logline-why {
    margin-top: 8px;
    padding-left: 10px;
    border-left: 2px solid var(--border);
    font-size: 14px;
    line-height: 1.45;
    color: var(--text-muted);
}

/* Supporting lines ------------------------------------------------------- */

.ai-meta {
    font-size: 14px;
    color: var(--text-muted);
    margin: 0 0 10px;
}

.ai-readback,
.ai-notes {
    margin-top: 12px;
    padding: 10px 12px;
    border-radius: 6px;
    background: var(--bg-light);
    font-size: 14px;
    line-height: 1.45;
    color: var(--text-soft);
}

.ai-cached-note {
    font-size: 13px;
    color: var(--text-muted);
    margin: 0 0 10px;
}

.ai-cached-note a {
    color: var(--primary);
    cursor: pointer;
}

/* Said once, quietly, and always -- the script is leaving the building and the
   writer is entitled to know that without having to go looking for it. */
.ai-disclaimer {
    margin-top: 12px;
    font-size: 12px;
    line-height: 1.4;
    color: var(--text-muted);
}

/* States ----------------------------------------------------------------- */

.ai-working {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 0;
    font-size: 15px;
    color: var(--text-muted);
}

.ai-error {
    margin-top: 10px;
    padding: 10px 12px;
    border-radius: 6px;
    border: 1px solid var(--border);
    background: var(--bg-light);
    font-size: 14px;
    color: var(--text-soft);
}

@media (max-width: 700px) {
    .ai-logline-head {
        align-items: flex-start;
        flex-direction: column;
    }
}

/* The writer's own logline, judged ---------------------------------------
   Sits above the alternatives: it is what they already have, and the three
   below only mean something once you know what is wrong with this one. */

.ai-yours {
    margin: 0 0 14px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-left: 3px solid var(--color-blue);
    border-radius: 6px;
    background: var(--bg-light);
}

.ai-yours-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-blue);
    margin-bottom: 6px;
}

/* Verdict and accuracy chips. The class is chosen from a whitelist server-side
   -- never from the model's own string -- so these three are the only ones
   that can appear, plus the neutral fallback. */
.ai-verdict,
.ai-accuracy {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.ai-verdict-strong {
    background: #d7f5e3;
    color: #1a7f4b;
}

.ai-verdict-workable {
    background: #fdf0d5;
    color: #8a6100;
}

.ai-verdict-needs-work {
    background: #fde0e0;
    color: #a02a2a;
}

.ai-verdict-neutral {
    background: #e5e5e5;
    color: var(--text-soft);
}

.ai-accuracy {
    background: #fff;
    border: 1px solid var(--border);
    color: var(--text-muted);
    text-transform: none;
    letter-spacing: 0;
    font-weight: 600;
}

.ai-yours-note,
.ai-yours-keep {
    margin: 0 0 4px;
    font-size: 14px;
    line-height: 1.45;
    color: var(--text-soft);
}

.ai-yours-keep {
    color: var(--text-muted);
}

/* What each alternative does that the writer's does not. Distinct from
   .ai-logline-why: that is why this version exists at all, this is the
   comparison, and they answer different questions. */
.ai-logline-vs {
    margin-top: 6px;
    padding-left: 10px;
    border-left: 2px solid var(--color-blue);
    font-size: 14px;
    line-height: 1.45;
    color: var(--text-soft);
}

.ai-logline-vs strong {
    color: var(--color-blue);
}

/* A result generated from a script or a logline that has since changed. Shown
   rather than hidden -- it is still the writer's work -- but it has to say so,
   or it silently describes a logline they have already rewritten. */
.ai-cached-stale {
    padding: 6px 10px;
    border-radius: 5px;
    background: #fdf0d5;
    color: #8a6100;
}

.ai-cached-stale a {
    color: #8a6100;
    text-decoration: underline;
}

/* For television: what the model reads the SHOW as. The loglines above it are
   selling the series, so this is the premise they are built on -- and the
   confidence note matters, because one episode is thin evidence for a series. */
.ai-series {
    margin: 0 0 12px;
    padding: 10px 14px;
    border: 1px dashed var(--border);
    border-radius: 6px;
}

.ai-series-head {
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    margin-bottom: 4px;
}

.ai-series-engine {
    margin: 0;
    font-size: 16px;
    line-height: 1.4;
    color: var(--text-soft);
}

.ai-series-foot {
    margin: 6px 0 0;
    font-size: 12px;
    color: var(--text-muted);
}

/* Shown where the Regenerate link would be, while the daily limit is in force.
   A link that always refuses is worse than no link. */
.ai-cooldown {
    color: var(--text-muted);
}

/* The collapsed line, and the history ------------------------------------
   What a writer returning to a script sees first: one small line saying the
   work exists and when it was done. The result is in the page underneath it,
   folded away, so opening it costs nothing. */

.ai-logline-summary {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-top: 8px;
}

.ai-summary-toggle,
.ai-history-open {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--text-muted);
    transition: color 0.2s;
}

.ai-summary-toggle:hover,
.ai-history-open:hover {
    color: var(--primary);
}

.ai-summary-chevron,
.ai-history-chevron {
    font-size: 11px;
    transition: transform 0.2s;
}

.ai-history-open {
    color: var(--color-blue);
}

/* The dialog ------------------------------------------------------------- */

.ai-history {
    padding: 4px 2px;
}

.ai-history-title {
    margin: 0 0 2px;
    font-size: 20px;
    color: var(--color-blue);
}

.ai-history-sub {
    margin: 0 0 14px;
    font-size: 13px;
    color: var(--text-muted);
}

.ai-history-entry {
    border-top: 1px solid var(--border);
    padding: 10px 0;
}

/* The set that still matches the script as it stands. */
.ai-history-entry.is-current {
    border-left: 3px solid var(--color-blue);
    padding-left: 10px;
}

.ai-history-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    text-align: left;
    font-family: var(--font-sans);
}

.ai-history-when {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-soft);
}

.ai-history-count {
    font-size: 13px;
    color: var(--text-muted);
}

.ai-history-badge {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 2px 8px;
    border-radius: 10px;
    background: var(--primary-dim, #eef0ff);
    color: var(--primary);
}

.ai-history-body {
    padding-top: 6px;
}

/* The story extract ------------------------------------------------------
   Folded away by default: it is a page of analysis on a card whose job is the
   script. The bar is always visible so the writer knows it exists. */

.ai-extract-offer {
    margin-top: 10px;
    padding: 12px 14px;
    border: 1px dashed var(--border);
    border-radius: 6px;
    /* The same size as every other tab's description (Ben, 2026-10-01). */
    font-size: .93rem;
    line-height: 1.5;
    color: var(--text-soft);
}

.ai-extract-offer p {
    margin: 0 0 10px;
}

.ai-extract-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 10px;
}

.ai-extract-toggle,
.ai-reanalyze {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--text-muted);
    transition: color 0.2s;
}

.ai-extract-toggle:hover,
.ai-reanalyze:hover {
    color: var(--primary);
}

.ai-extract-panel {
    margin-top: 10px;
}

/* An out-of-date breakdown is not a warning.
 *
 * This was amber on amber -- the palette this file uses for things that went
 * wrong (.cv-verdict--consider, the error notes at 223 and 280) -- and it was
 * raised by a single comma, because a hash cannot tell a comma from a rewrite.
 * A writer who sees a caution strip every time they touch their own script
 * learns to stop touching it, which is the opposite of the point.
 *
 * So: grey, a hairline instead of a fill, and the same muted tone as the pass
 * verdict. It is still there, still first, still noticed. It just is not
 * shouting, because nothing here is broken -- the panel below it works, and the
 * note is an offer to refresh it whenever the changes have earned it.
 */
.ai-extract-stale {
    margin-bottom: 12px;
    padding: 8px 12px;
    border-radius: 6px;
    background: #f7f8f9;
    border: 1px solid #e6e8ea;
    color: #5b6167;
    font-size: 13px;
    line-height: 1.45;
}

.ai-extract-stale i {
    margin-right: 5px;
    color: #99a0a7;
}

/* Boxed, like a coverage category ---------------------------------------------

   These were a flat run of small headings with paragraphs under them, which
   on a reading of fifteen fields gave the eye nothing to stop at -- Story ran
   into Character ran into Structure, and the writer had to read the labels to
   find out where they were.

   Same box as .cv-cat on the coverage report, on purpose: the two are read by
   the same person on the same page, and a report that looks like a different
   product for being a different feature is just harder to use. */
.ai-x-section,
.ai-x-list {
    margin-bottom: 12px;
    padding: 14px 16px;
    border: 1px solid var(--border, #e6e6e6);
    border-radius: 6px;
    background: #fcfcfc;
}

/* A heading now, not a label on a paragraph. 1.2rem and uppercase is what
   .cv-cat-name settled on for the same job. */
.ai-x-section-title {
    margin: 0 0 10px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border, #ececec);
    font-size: 1.2rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-blue);
}

/* Label above value, with air between fields.

   8px was fine when the whole section was small; inside a box with a rule
   under its heading, the fields need to be told apart from each other as well
   as from the heading. The last one drops its margin so the box does not end
   with a gap. */
.ai-x-field {
    margin-bottom: 12px;
}

.ai-x-section .ai-x-field:last-child { margin-bottom: 0; }

/* The subheading. Uppercase and small against a 1.2rem section title, so the
   two never compete: one names the section, the other names the field. */
.ai-x-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--text-muted);
    margin-bottom: 3px;
}

/* A field the writer changed says so, and offers the way back. */
.ai-x-edited {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 1px 6px;
    border-radius: 8px;
    background: var(--bg-light);
    color: var(--text-soft);
}

.ai-x-revert,
.ai-x-promote {
    padding: 1px 8px;
    border: 1px solid var(--border);
    border-radius: 5px;
    background: #fff;
    cursor: pointer;
    font-family: var(--font-sans);
    font-size: 11px;
    color: var(--text-muted);
    transition: all 0.2s;
}

.ai-x-revert:hover,
.ai-x-promote:hover {
    border-color: var(--primary);
    color: var(--primary);
}

/* contenteditable, not an input: the card is a reading surface, and a page of
   boxes reads as a form to fill in rather than an analysis to correct. */
/* Reads as prose, and still says it is editable on hover. The negative left
   margin puts the text back on the box's own left edge, so the padding that
   exists for the hover outline does not indent every value by 10px. */
.ai-x-value {
    margin-left: -10px;
    padding: 3px 10px;
    border: 1px solid transparent;
    border-radius: 5px;
    font-size: 1.05rem;
    line-height: 1.55;
    color: var(--text-soft);
    transition: all 0.15s;
}

/* ONLY THE ONES THAT CAN ACTUALLY BE EDITED.
 *
 * The outline on hover is an invitation: it says this line is yours to
 * correct. On a Library listing it is not -- renderExtract() is called with
 * readonly there and leaves contenteditable off -- and a box that lights up
 * under the pointer and then refuses to take a caret is a promise the page
 * cannot keep.
 *
 * The attribute is the test rather than a class of its own, because the
 * attribute IS the difference: it is what makes the line editable, so it
 * cannot fall out of step with whether the line is editable. */
.ai-x-value[contenteditable]:hover {
    border-color: var(--border);
    background: #fff;
}

.ai-x-value[contenteditable]:focus {
    outline: none;
    border-color: var(--primary);
    background: #fff;
}

.ai-x-list {
    margin-bottom: 14px;
}

.ai-x-list ul {
    margin: 0;
    padding-left: 18px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-soft);
}

.ai-x-page {
    font-size: 11px;
    color: var(--text-muted);
}

.ai-x-chip {
    display: inline-block;
    margin: 0 4px 4px 0;
    padding: 2px 10px;
    border-radius: 10px;
    background: var(--bg-light);
    font-size: 13px;
    color: var(--text-soft);
}

.ai-x-confidence {
    padding: 10px 12px;
    border-radius: 6px;
    background: var(--bg-light);
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-soft);
}

/* Feedback --------------------------------------------------------------- */

.ai-logline-vote {
    display: inline-flex;
    gap: 4px;
    margin-left: auto;
}

.ai-logline-vote button {
    padding: 4px 10px;
    border: 1px solid var(--border);
    border-radius: 5px;
    background: #fff;
    cursor: pointer;
    font-size: 12px;
    color: var(--text-muted);
    transition: all 0.2s;
}

.ai-logline-vote button:hover {
    border-color: var(--primary);
    color: var(--primary);
}

.ai-logline-vote button.is-on {
    border-color: var(--color-blue);
    background: var(--bg-light);
    color: var(--color-blue);
}

/* .ai-reason, .ai-reason-input, .ai-reason-send and .ai-reason-thanks are
   defined further down, where the note box became a label above a growing
   textarea above a button. They used to live here as a single flex row, and
   leaving that behind kept the label on the same line as the field. */

/* A column now: the standing note sits above the button, full width, and the
   button and its hint stay a row of their own. */
.ai-refine-row {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    margin-top: 14px;
}

.ai-refine-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.ai-refine-hint {
    font-size: 12px;
    color: var(--text-muted);
}

/* The standing note ------------------------------------------------------

   Shaped like .ai-reason on purpose. It asks the same kind of thing -- tell
   us what you think -- and a writer who has met one of these boxes under a
   logline should recognise this one without being taught it twice. What it
   does not have is a Save button: this one saves itself. */
.ai-note {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
}

.ai-note .grow-wrap {
    width: 100%;
}

.ai-note-ask {
    display: block;
    margin-bottom: 4px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-dark, #222);
}

.ai-note-optional {
    font-weight: 400;
    font-style: italic;
    color: var(--text-soft, #6b6b6b);
}

.ai-note .grow-wrap>textarea,
.ai-note .grow-wrap::after {
    font-size: 0.92rem;
    line-height: 1.45;
    padding: 6px 9px;
    border-radius: 6px;
    font-family: inherit;
    min-height: 2.6em;
}

.ai-note .grow-wrap>textarea:focus {
    outline: none;
    border-color: var(--logo-green, #2e7d5b);
}

/* Holds its line whether or not it has anything to say, so the button below
   does not jump when a save reports back. */
.ai-note-state {
    display: block;
    min-height: 1.1em;
    margin-top: 4px;
    font-size: 12px;
    font-style: italic;
    color: var(--text-muted);
}

/* Refine's read-back of the writer's notes. First thing in the result, because
   somebody who has just rated three loglines wants to see their notes landed. */
.ai-responding {
    margin: 0 0 12px;
    padding: 10px 12px;
    border-left: 3px solid var(--color-blue);
    border-radius: 4px;
    background: var(--bg-light);
    font-size: 14px;
    line-height: 1.45;
    color: var(--text-soft);
}

/* The structure pass, running quietly beside the analysis bar. */
.ai-mapping {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-left: auto;
    font-size: 12px;
    color: var(--text-muted);
}

/* Credits ---------------------------------------------------------------- */

.ai-logline-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}

.ai-credit-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border: 1px solid var(--border, #d8d8d8);
    border-radius: 999px;
    font-size: 0.9rem;
    line-height: 1.6;
    color: var(--text-muted, #6b6b6b);
    white-space: nowrap;
}

.ai-credit-pill i {
    font-size: 0.72rem;
    opacity: 0.75;
}

/* The price confirmation ------------------------------------------------- */

.ai-quote-parts {
    list-style: none;
    margin: 0 0 12px;
    padding: 0;
    text-align: left;
}

/* No rules between the rows.

   Each line item can carry a note under it, and a border fell between the two
   -- so 'Read and analyse the script' and the sentence explaining why it is on
   the bill read as two separate charges. The rule under .ai-quote-total is the
   only division this list needs: everything above it is what you are buying,
   and the thing below is what it comes to. */
.ai-quote-parts li {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 5px 0;
}

.ai-quote-total {
    margin: 0;
}

/* Said above the price when the writer has rated loglines without saying why.
   Left-aligned against the dialog's centred text on purpose: it is two
   sentences of explanation, and centred prose is read as a headline. */
.ai-brief-thin {
    margin: 0 0 10px;
    text-align: left;
    font-size: 0.92rem;
    line-height: 1.5;
    color: var(--text-soft, #6b6b6b);
}

.ai-brief-thin+.ai-quote-total {
    padding-top: 10px;
    border-top: 1px solid var(--border, #e6e6e6);
}

/* The fallback shape, for a quote with no line items to hang a note on.
   No rule of its own: it drew one above itself, which put the note below a
   border and made it read as a second total rather than as a caution. */
.ai-quote-warning {
    margin: 12px 0 0;
    font-size: 0.9em;
    color: var(--text-muted, #6b6b6b);
}

/* And the usual shape: an aside like the others, but the one that says what
   you are about to lose. Darker than a plain note and not italic, because it
   is a caution rather than a footnote. */
.ai-quote-parts li.ai-quote-warn-note {
    padding-top: 6px;
    font-style: normal;
    color: var(--text-dark, #444);
}

/* The credits page ------------------------------------------------------- */

.credit-summary {
    padding: 10px;
}

.credit-figure {
    display: flex;
    align-items: baseline;
    gap: 10px;
}

.credit-figure-value {
    font-size: 2.4rem;
    font-weight: 700;
    line-height: 1;
    color: var(--logo-green, #2e7d5b);
}

.credit-figure-label {
    font-size: 0.95rem;
    color: var(--text-soft, #6b6b6b);
}

.credit-split {
    margin: 10px 0 0;
    font-size: 0.92rem;
    color: var(--text-soft, #6b6b6b);
}

.credit-actions {
    margin-top: 16px;
}

.credit-pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    padding: 14px 0 4px;
}

.credit-pager:empty {
    display: none;
}

.credit-pager-label {
    font-size: 0.9rem;
    color: var(--text-soft, #6b6b6b);
}

a.ai-credit-pill {
    text-decoration: none;
}

a.ai-credit-pill:hover {
    border-color: var(--logo-green, #2e7d5b);
    color: var(--logo-green, #2e7d5b);
}

/* A credit balance just after a widget's title -- AI credits beside AI
   Extras, Review Credits beside Member Reviews (2026-10-04). Inside the
   heading, so it is set back to the pill's own lettering. */
.block-title .title-credit-pill {
    margin-left: 10px;
    vertical-align: middle;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
}

/* Choosing a credit pack ------------------------------------------------- */

.credit-pack-intro {
    margin: 0 0 16px;
    font-size: 0.92rem;
    color: var(--text-soft, #6b6b6b);
}

.credit-pack {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: 100%;
    margin-bottom: 10px;
    padding: 14px 16px;
    border: 1px solid var(--border, #d8d8d8);
    border-radius: 8px;
    background: var(--bg-white, #fff);
    cursor: pointer;
    text-align: left;
    transition: border-color .15s, background .15s;
}

.credit-pack:hover:not(:disabled) {
    border-color: var(--logo-green, #2e7d5b);
    background: var(--bg-light, #f7f7f7);
}

.credit-pack:disabled {
    opacity: 0.55;
    cursor: default;
}

.credit-pack-main {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.credit-pack-credits {
    font-weight: 600;
    font-size: 1.05rem;
}

.credit-pack-rate,
.credit-pack-price {
    font-size: 0.88rem;
    color: var(--text-soft, #6b6b6b);
}

.credit-pack-price {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--logo-green, #2e7d5b);
    white-space: nowrap;
}

/* The member discount: the line over the packs, and the regular price struck
   through beside a member's own. */
.credit-pack-note {
    margin: 0 0 12px;
    padding: 8px 12px;
    border-radius: 6px;
    background: var(--bg-light, #f7f7f7);
    font-size: 0.92rem;
}

.credit-pack-note i {
    color: var(--logo-green, #2e7d5b);
    margin-right: 4px;
}

.credit-pack-note a {
    font-weight: 600;
    white-space: nowrap;
}

/* A sale running on the packs (store_sales): first, and set apart from the
   membership note under it. */
.credit-pack-sale {
    border: 1px solid var(--logo-green, #2e7d5b);
    background: rgba(46, 125, 91, 0.08);
}

.credit-pack-cost {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
}

.credit-pack-was {
    font-size: 0.9rem;
    color: var(--text-soft, #6b6b6b);
    text-decoration: line-through;
    white-space: nowrap;
}

/* AI Extras widget --------------------------------------------------------
   The tab chrome is the site's own (.nav-tabs / .tab-pane, as used by Script
   Elements and Attachments/Media). Only the inside of a pane needs anything. */

.ai-extras {
    margin-bottom: 18px;
}

/* The Coverage widget. It carries .ai-extras for the spacing and for the
   rules its contents already expect, and has no tabs -- so the padding a tab
   pane would give (10px, see .tab-pane in dashboard.css) plus the side
   padding of .ai-extras-panes is given here instead. */
.cover-widget-body {
    padding: 10px;
}

/* The buttons in the Coverage head, pushed to the right edge as one group --
   the job .list-tools does for the dashboard's Folders head. Inside it each
   .btn-script's own margin-left: auto has no free space to take, so it
   resolves to nothing and the gap alone spaces them. */
.cover-head-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}

/* The row the Generate and Review buttons sit in.

   No padding at the top. The tab pane already opens with its own space, so
   12px more here pushed the buttons a clear line further down than anything
   above them warranted -- two rules each doing a bit of the same job, which
   is how a gap ends up bigger than either author intended. */
.ai-tab-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    /* Nothing above -- the tab pane opens the space there -- and room below,
       because the panels that follow are bordered boxes. Butted up against
       one, a button reads as part of its header rather than as the thing
       that made it. The 4px this replaces was doing nothing visible. */
    padding: 0;
    margin-bottom: 14px;
}

.ai-tab-foot {
    padding: 10px 0 4px;
    border-top: 1px solid var(--border, #e6e6e6);
    margin-top: 12px;
}

.ai-tab-empty {
    margin: 0;
    padding: 22px 4px;
    text-align: center;
    color: var(--text-soft, #6b6b6b);
    font-size: 0.95rem;
}

/* The analysis is the tab's whole content now, so it no longer hides itself
   behind a chevron -- the tab is the disclosure. */
.ai-extras .ai-extract-panel {
    padding-top: 4px;
}

.ai-extract-note {
    font-size: 0.85rem;
    color: var(--text-soft, #6b6b6b);
    font-style: italic;
}

/* An edited logline ------------------------------------------------------- */

.ai-logline-text[contenteditable] {
    border-radius: 4px;
    padding: 2px 4px;
    margin: -2px -4px;
    outline: none;
    transition: background .15s, box-shadow .15s;
}

.ai-logline-text[contenteditable]:hover {
    background: var(--bg-light, #f7f7f7);
}

.ai-logline-text[contenteditable]:focus {
    background: var(--bg-white, #fff);
    box-shadow: 0 0 0 2px var(--logo-green, #2e7d5b);
}

.ai-logline-edited {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
    font-size: 0.78rem;
    font-style: italic;
    color: var(--text-soft, #6b6b6b);
}

.ai-logline-revert {
    border: 0;
    background: none;
    padding: 0 2px;
    cursor: pointer;
    color: var(--text-soft, #6b6b6b);
    font-size: 0.78rem;
}

.ai-logline-revert:hover {
    color: var(--logo-green, #2e7d5b);
}

/* Telling us why ---------------------------------------------------------- */

.ai-reason {
    /* A column: the question, then the field, then the button. Explicit
       rather than relying on block flow, so this cannot be quietly turned
       back into a row by a rule defined above it. */
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    margin-top: 10px;
    width: 100%;
}

.ai-reason .grow-wrap {
    width: 100%;
}

.ai-reason-ask {
    display: block;
    margin-bottom: 4px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-dark, #222);
}

.ai-reason-optional {
    font-weight: 400;
    font-style: italic;
    color: var(--text-soft, #6b6b6b);
}

/* The wrapper is css/dashboard.css's .grow-wrap. Only the size is overridden
   here -- this sits inside a logline, not in a dialog. */
.ai-reason .grow-wrap>textarea,
.ai-reason .grow-wrap::after {
    font-size: 0.92rem;
    line-height: 1.45;
    padding: 6px 9px;
    border-radius: 6px;
    font-family: inherit;
    min-height: 2.2em;
}

.ai-reason .grow-wrap>textarea:focus {
    outline: none;
    border-color: var(--logo-green, #2e7d5b);
}

.ai-reason-send {
    margin-top: 6px;
    padding: 4px 14px;
    border: 1px solid var(--border, #d8d8d8);
    border-radius: 6px;
    background: var(--bg-white, #fff);
    font-size: 0.85rem;
    cursor: pointer;
}

.ai-reason-send:hover {
    border-color: var(--logo-green, #2e7d5b);
    color: var(--logo-green, #2e7d5b);
}

.ai-reason-thanks {
    font-size: 0.85rem;
    font-style: italic;
    color: var(--text-soft, #6b6b6b);
}

/* Choosing the angles ----------------------------------------------------- */



/* Choosing a style, in the Generate dialog -------------------------------- */

.ai-angle-intro {
    margin: 0 0 10px;
    text-align: left;
    font-size: 0.95rem;
}

.ai-angle-choices {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 16px;
    text-align: left;
}

.ai-angle-choice {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border, #d8d8d8);
    border-radius: 8px;
    cursor: pointer;
    transition: border-color .15s, background .15s;
}

.ai-angle-choice:hover {
    background: var(--bg-light, #f7f7f7);
}

/* :has is what lets the whole row respond to its own radio. Where it is not
   supported the rows simply stay plain, which is a smaller loss than wiring
   a class up in script. */
.ai-angle-choice:has(input:checked) {
    border-color: var(--logo-green, #2e7d5b);
    background: var(--bg-light, #f7f7f7);
}

.ai-angle-choice input {
    margin-top: 3px;
    flex: none;
}

.ai-angle-choice-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ai-angle-choice-label {
    font-weight: 600;
    font-size: 0.95rem;
}

.ai-angle-choice-blurb {
    font-size: 0.85rem;
    color: var(--text-soft, #6b6b6b);
}

/* Guidance, asked in the same dialog as the style ------------------------

   A plain textarea rather than a .grow-wrap: this one sits in a dialog that
   sizes itself to its content, and a field that grows as it is typed into
   would move the Generate button down the screen under the writer's cursor.
   Three rows, and it scrolls. */
.ai-angle-note-ask {
    display: block;
    margin: 16px 0 4px;
    text-align: left;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text-dark, #222);
}

.ai-angle-note-optional {
    font-weight: 400;
    font-style: italic;
    color: var(--text-soft, #6b6b6b);
}

textarea.ai-angle-note {
    display: block;
    width: 100%;
    box-sizing: border-box;
    padding: 8px 10px;
    border: 1px solid var(--border, #d8d8d8);
    border-radius: 8px;
    font-family: inherit;
    font-size: 0.92rem;
    line-height: 1.45;
    resize: vertical;
}

textarea.ai-angle-note:focus {
    outline: none;
    border-color: var(--logo-green, #2e7d5b);
}

/* Says the note outlives this dialog, which is the part a writer would not
   otherwise guess: it reads like a field on a form, and it is a setting. */
/* The gap between the note and the price lives here rather than on the price
   itself: the analyse dialog shows the same price line with no note above it,
   and spacing it from there would open a hole at the top of that one. */
.ai-angle-note-hint {
    margin: 4px 0 24px;
    text-align: left;
    font-size: 12px;
    font-style: italic;
    color: var(--text-muted);
}

/* And less between the price and the buttons than SweetAlert's own 1.25em.
   The total is the last thing read before deciding, so it belongs with the
   button that acts on it rather than floating between the two. */
.ai-quote-popup .swal2-actions {
    margin-top: 10px;
}

/* Said above the price when a script is short for its format. Amber rather
   than red: it is a caution about what the answer will be like, not a refusal
   -- the refusals never reach a dialog at all. */
.ai-length-warn {
    margin: 0 0 12px;
    padding: 8px 10px;
    border-radius: 6px;
    background: var(--bg-warning-soft, #fdf6e3);
    border: 1px solid var(--warning, #e0b84c);
    text-align: left;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--text-dark, #333);
}

.ai-length-warn i {
    margin-right: 6px;
    color: var(--warning, #c9971f);
}

/* A read on the writer's own logline -------------------------------------- */

.ai-review-out:empty {
    display: none;
}

.ai-review {
    margin-bottom: 14px;
    padding: 14px;
    border: 1px solid var(--border, #e2e2e2);
    border-radius: 10px;
    background: var(--bg-white, #fff);
}

/* The answer first. A writer asked one question and it should not be below a
   table of criteria they have to read down to find it. */
.ai-review-verdict {
    padding-left: 12px;
    border-left: 4px solid var(--border, #d8d8d8);
}

.ai-review-verdict.is-yes {
    border-left-color: var(--logo-green, #2e7d5b);
}

.ai-review-verdict.is-maybe {
    border-left-color: var(--warning, #e0b84c);
}

.ai-review-verdict.is-no {
    border-left-color: var(--danger, #b4462f);
}

.ai-review-badge {
    display: inline-block;
    margin-bottom: 4px;
    font-size: 1.05rem;
    font-weight: 700;
}

.is-yes .ai-review-badge {
    color: var(--logo-green, #2e7d5b);
}

.is-maybe .ai-review-badge {
    color: var(--warning, #b8901f);
}

.is-no .ai-review-badge {
    color: var(--danger, #b4462f);
}

.ai-review-summary {
    margin: 0;
    font-size: 0.95rem;
    line-height: 1.55;
}

.ai-review-reads {
    margin: 12px 0 0;
    font-size: 0.9rem;
}

.ai-review-mismatch {
    display: block;
    margin-top: 4px;
    color: var(--warning, #b8901f);
}

/* One thing to keep, one thing to change. */
.ai-review-headline {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin: 14px 0;
}

@media (max-width: 620px) {
    .ai-review-headline {
        grid-template-columns: 1fr;
    }
}

.ai-review-keep,
.ai-review-fix {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 10px;
    border-radius: 8px;
    background: var(--bg-light, #f7f7f7);
    font-size: 0.9rem;
    line-height: 1.5;
}

.ai-review-keep strong {
    color: var(--logo-green, #2e7d5b);
}

.ai-review-fix strong {
    color: var(--danger, #b4462f);
}

.ai-review-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.ai-review-item {
    display: grid;
    grid-template-columns: 8.5rem 5.5rem 1fr;
    gap: 10px;
    align-items: baseline;
    padding: 8px 0;
    border-top: 1px solid var(--border, #eee);
    font-size: 0.9rem;
    line-height: 1.5;
}

@media (max-width: 620px) {
    .ai-review-item {
        grid-template-columns: 1fr;
        gap: 2px;
    }
}

.ai-review-crit {
    font-weight: 600;
}

.ai-review-rating {
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .02em;
}

.ai-review-rating.is-strong {
    color: var(--logo-green, #2e7d5b);
}

.ai-review-rating.is-adequate {
    color: var(--text-muted, #8a8a8a);
}

.ai-review-rating.is-weak {
    color: var(--danger, #b4462f);
}

.ai-review-missing {
    margin-top: 12px;
    font-size: 0.9rem;
    line-height: 1.5;
}

.ai-review-missing ul {
    margin: 4px 0 0;
    padding-left: 18px;
}

/* The basis of the whole read, said plainly: a writer who assumes otherwise
   would take "would pass" as a verdict on their screenplay. */
.ai-review-scope {
    margin: 14px 0 0;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-muted, #8a8a8a);
}

/* The two rewrites --------------------------------------------------------

   Copy, never adopt. The visual difference between them is the whole point:
   one is the writer's own sentence rebuilt, the other is fiction that happens
   to be well shaped, and they must not read as two versions of one thing. */
.ai-rw {
    margin-top: 14px;
    padding: 12px;
    border-radius: 8px;
    border: 1px solid var(--border, #e2e2e2);
}

.ai-rw-tight {
    background: var(--bg-light, #f7f7f7);
}

/* Dashed and tinted: it looks provisional because it is. */
.ai-rw-made {
    background: var(--bg-warning-soft, #fdf9ef);
    border-style: dashed;
    border-color: var(--warning, #e0b84c);
}

.ai-rw-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 6px;
    font-size: 0.9rem;
}

.ai-rw-tag {
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--bg-white, #fff);
    border: 1px solid var(--border, #d8d8d8);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--text-muted, #8a8a8a);
}

.ai-rw-tag.is-warn {
    border-color: var(--warning, #e0b84c);
    color: var(--warning, #b8901f);
}

.ai-rw-text {
    margin: 0 0 6px;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--text-dark, #222);
}

.ai-rw-why {
    margin: 0 0 8px;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-soft, #6b6b6b);
}

.ai-rw-warn {
    margin: 0 0 8px;
    font-size: 0.85rem;
    line-height: 1.5;
    font-weight: 600;
    color: var(--text-dark, #333);
}

.ai-rw-warn i {
    margin-right: 5px;
    color: var(--warning, #c9971f);
}

.ai-rw-invented {
    margin-bottom: 8px;
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--text-soft, #6b6b6b);
}

.ai-rw-invented ul {
    margin: 3px 0 0;
    padding-left: 18px;
}

.ai-rw-copy {
    padding: 3px 12px;
    border: 1px solid var(--border, #d8d8d8);
    border-radius: 6px;
    background: var(--bg-white, #fff);
    font-size: 0.82rem;
    cursor: pointer;
}

.ai-rw-copy:hover {
    border-color: var(--logo-green, #2e7d5b);
    color: var(--logo-green, #2e7d5b);
}

/* The collapsible sections ------------------------------------------------

   One shape for all three long answers -- the story analysis, the suggested
   loglines, the logline review. They are the same kind of thing to a reader
   and any difference between them would only be noise. */
.ai-panel {
    display: block;
    margin-bottom: 9px;
    border: 1px solid var(--border, #e2e2e2);
    border-radius: 10px;
    overflow: hidden;
}

/* A panel is two tones, both warm: the head a light beige, the body a much
   lighter one -- see --panel-head-bg and --panel-body-bg in css/global.css.
   Grey is what every surface around these already is, so a grey bar on a grey
   body had nothing to say it was the thing to press. */
.ai-panel-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    border: 0;
    background: var(--panel-head-bg, #f1eadb);
    text-align: left;
    cursor: pointer;
    font-family: inherit;
}

/* A head with a control beside it.

   Three things on one bar, in reading order: the title, the control that
   belongs to this section, then the answer in miniature pushed to the far
   right. The control cannot be inside the head -- it is a checkbox and the
   head is a <button> -- so all three are siblings here and the row is what
   makes them a line.

   center, not baseline: the switch is a drawn track rather than text and has
   no baseline worth aligning to, so matching baselines is what made it sit
   low against the words either side of it. */
.ai-panel-headrow {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--panel-head-bg, #f1eadb);
    cursor: pointer;
}

/* Sized to its own contents, so the control sits directly after the title
   instead of being pushed across a button that had stretched to fill the bar.

   AND THEREFORE NOT THE THING THAT LIGHTS UP

   A full-width head painted its own hover and the whole bar responded. Shrunk
   to its contents it darkened the words 'Coverage Sep 6, 2026' and nothing
   else, which reads as a bug: the bar is clickable end to end -- see the
   .ai-panel-headrow branch in js/ai-logline.js -- so a highlight covering a
   third of it describes something that is not true.

   The button goes transparent in here and the row paints both states, so the
   highlight matches the click target exactly.

   Kept as a <button> rather than swapped for a div with an onclick, which was
   the other way to fix this. The hover is a styling problem and this is a
   styling answer; changing the element would trade it for a control that
   cannot be tabbed to or fired with Enter, and getting those back means a
   tabindex, a role and a keydown handler -- three things to keep working in
   place of one line. */
.ai-panel-headrow>.ai-panel-head {
    /* width:auto beats the base rule's width:100%, which is the whole of why
       this needs saying. flex:0 1 auto resolves its basis from width, so a
       button still asking for 100% took the entire bar however little text was
       in it -- shoving the switch to the far right and squeezing the verdict
       until it ellipsised. Sized to its content, the three parts sit in reading
       order with the room going to the verdict, which is what needs it. */
    width: auto;
    flex: 0 1 auto;
    min-width: 0;
    align-items: center;
    padding-right: 0;
    background: transparent;
}

.ai-panel-headrow>.ai-panel-head:hover {
    background: transparent;
}

/* Deeper than the beige the bar rests at, and warm like it: --bg-hover is a
   grey, and against the head's own tone it read as the bar going cold under
   the pointer rather than lighting up. */
.ai-panel-headrow:hover {
    background: var(--panel-head-hover, #e9e1cd);
}


/* Outside the button in this arrangement, so it needs the stretch and the
   right-hand padding the button used to give it. */
.ai-panel-headrow>.ai-panel-meta {
    flex: 1 1 auto;
    padding-right: 12px;
}

/* Never squeezed by the line beside it, and never the thing that wraps.

   Its own cursor, because it is the one stretch of the bar that toggles
   nothing and must not offer the pointer that says it does. The switch inside
   sets pointer on itself, which beats this inherited one. */
.ai-panel-aside {
    flex: none;
    display: flex;
    align-items: center;
    cursor: default;
}

/* The switch was drawn for a stacked block, where it needs room above it.
   On one line with everything else that margin is what drops it below the
   text it is supposed to be level with. */
.ai-panel-aside .mk-switch {
    margin-top: 0;
}

.ai-panel-aside .mk-switch-text {
    font-size: 14px;
    white-space: nowrap;
}

/* The two coverage switches -- summary page and Browse Coverage -- side by
   side in the head, stacking once the head is too narrow to hold both beside
   the title. */
.cv-switches {
    display: flex;
    align-items: center;
    gap: 6px 16px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

@media (max-width: 720px) {
    .cv-switches {
        flex-direction: column;
        align-items: flex-start;
    }
}

.ai-panel-head:hover {
    background: var(--panel-head-hover, #e9e1cd);
}

.ai-panel-chevron {
    flex: none;
    font-size: 0.8rem;
    color: var(--text-muted, #8a8a8a);
}

/* Uppercase and blue, the way every other section label on these pages is set
   -- .script-section-label in css/dashboard.css -- so a panel head reads as
   the name of a section rather than a sentence. The tracking comes with the
   uppercase: bold capitals at this size set solid look cramped.

   The icon keeps its own colour: .ai-panel-title-icon below sets it, and a
   colour on the span cannot reach past that. */
.ai-panel-title {
    font-weight: 700;
    font-size: 0.95rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--color-blue, #005e6a);
}

/* Coverage titles carry a date -- 'Coverage Sep 6, 2026' -- which is what
   tells one report from another in a stack, so it stays on one line.
   It used to be set larger than the rest as well; it is not any more. Every
   accordion title on the site is one size, and a panel that shouted was a
   panel claiming to matter more than the one above it. */
.ai-panel[data-panel^="coverage"] .ai-panel-title {
    white-space: nowrap;
}

/* Who wrote it, before the title: the wand on a report the AI wrote. The same
   colour Browse Coverage gives its wand (.bc-source--ai). */
.ai-panel-title-icon {
    margin-right: 7px;
    color: var(--accent-primary);
    cursor: help;
}

/* The answer in miniature, kept visible when the panel is shut so a closed
   section still says something. Pushed right, and first to go on a narrow
   screen -- the title is what has to survive. */
.ai-panel-meta {
    flex: 1;
    text-align: right;
    font-size: 0.82rem;
    color: var(--text-muted, #8a8a8a);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The paper under the bar. Said here rather than left to whatever the panel
   happens to be sitting on: these are drawn on the dashboard, on a public
   link and on a Script Library listing, and an open panel took a different
   colour on each of them. */
.ai-panel-body {
    padding: 12px;
    background: var(--panel-body-bg, #fdfbf5);
}

/* The contents already carried their own outside margin, which doubles up
   inside a bordered panel. */
.ai-panel-body>.ai-logline-result,
.ai-panel-body>.ai-review,
.ai-panel-body>.ai-extract {
    margin-bottom: 0;
}

/* The review keeps its own padding inside the panel -- its contents sit flush
   against the edge without it. The border goes, because the panel already
   draws one and two nested boxes read as two things. */
.ai-panel-body>.ai-review {
    padding: 10px;
    border: 0;
}

/* A review of a logline the writer has since changed. */
.ai-review-stale {
    margin: 0 0 12px;
    padding: 8px 10px;
    border-radius: 6px;
    background: var(--bg-light, #f6f6f6);
    font-size: 0.88rem;
    line-height: 1.5;
    color: var(--text-soft, #6b6b6b);
}

.ai-review-stale i {
    margin-right: 6px;
}

/* The line under the "place them all" question that says what will be lost. */
.ai-place-note {
    margin: 10px 0 0;
    font-size: 0.88rem;
    line-height: 1.5;
    color: var(--text-soft, #6b6b6b);
}

.ai-angle-choice-label em {
    font-weight: 400;
    font-style: normal;
    color: var(--text-muted, #8a8a8a);
}

/* The droppable line item ------------------------------------------------- */

/* The rebuild box on Re-analyse wears this too. It is the same kind of choice
   -- a thing this run will or will not do -- and it was setting its own size,
   which made it the one checkbox in the dialog that did not match. Sharing the
   rule is what stops that happening again. */
.ai-quote-pick label,
.ai-rebuild-pick label {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    margin: 0;
}

.ai-quote-pick input,
.ai-rebuild-pick input {
    flex: none;
    cursor: pointer;
}

/* Unticked, the row says what it would have cost rather than disappearing --
   the writer needs to see what they turned off, and what turning it back on
   would add.

   Greyed and nothing else. The strike through the number said the same thing
   the fading already said, twice, and read as a price that had been cancelled
   rather than one not being charged yet. */
.ai-quote-pick:has(input:not(:checked)) {
    opacity: .55;
}

/* A total, once there is a list above it to total up. */
.ai-quote-parts+.ai-quote-total {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 2px solid var(--border, #e6e6e6);
    font-weight: 600;
}

/* The Analysis tab's actions ---------------------------------------------- */

/* Buttons, not links. These sit alone on a bar with nothing else on it, so a
   borderless label with only a colour change on hover read as text that
   happened to be clickable -- and with the note beside them empty, the
   space-between pushed the first one into the middle of the tab. */
.ai-extract-bar {
    justify-content: flex-start;
}

.ai-extract-note {
    flex: 1;
}

.ai-extract-actions {
    display: flex;
    gap: 8px;
    margin-left: auto;
}

.ai-extract-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border: 1px solid var(--border, #d8d8d8);
    border-radius: 6px;
    background: var(--bg-white, #fff);
    cursor: pointer;
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--text-muted, #8a8a8a);
    transition: color .15s, border-color .15s, background .15s;
}

.ai-extract-btn:hover {
    background: var(--bg-light, #f6f6f6);
    border-color: var(--primary, #2e7d5b);
    color: var(--primary, #2e7d5b);
}

.ai-extract-btn:disabled {
    opacity: .6;
    cursor: default;
}

/* The structure choice as a section of its own is now the layout dialog's
   alone -- the analyse dialog asks it under the checkbox it belongs to, as
   .ai-quote-opt. Nothing greys this one: the layout dialog is buying the
   layout and nothing else, so the question can never be moot. The .is-off
   and .ai-shape-off rules that handled that went with it. */

/* The cost column ---------------------------------------------------------

   'credits' rides along with the number so the word wraps and aligns with it
   rather than being stranded on its own. nowrap because "8 / credits" over two
   lines in a two-column row looks like a fault. */
.ai-quote-cost {
    flex: none;
    white-space: nowrap;
    color: var(--text-muted, #8a8a8a);
}

.ai-quote-cost b {
    color: var(--text-dark, #222);
}

/* What happens if you say no to the optional line. A row of the same list, so
   it sits under the thing it is about -- but with no rule above it and no
   price, because it is not a charge.

   QUALIFIED WITH THE LIST, AND IT HAS TO BE

   .ai-quote-parts li is a class and a type, which outweighs a bare class --
   so every property the two share was being decided by the row rule and not
   by this one. The display went back to flex, and the 26px indent that ties
   the note to the checkbox above it was replaced by the row's 5px 0. It read
   as a rule that did nothing, because most of it did nothing.

   No vertical padding and a tighter line: two of these now sit in the
   analyse dialog, and the height they cost is height the buttons lose.

   The rebuild note is in this rule for a reason worth remembering: the
   selector is .ai-quote-parts li.ai-quote-aside, which is scoped to the list,
   so the same class on a div OUTSIDE it inherited none of this -- and the note
   came out upright, full size and the wrong colour. */
/* .ai-quote-solo is the same note on a quote that has no list to sit in --
   a single-item price, where the aside is the only explanation there is. It
   takes the list's styling but not its indent: with no line item above it,
   26px of hanging space is an indent under nothing. */
.ai-quote-parts li.ai-quote-aside,
.ai-quote-aside.ai-quote-solo,
.ai-rebuild-pick .ai-quote-aside {
    display: block;
    padding: 0 0 4px 26px;
    font-size: 0.85rem;
    font-style: italic;
    line-height: 1.3;
    color: var(--text-muted, #8a8a8a);
}

/* Qualified with the list, because .ai-quote-parts li is more specific than a
   bare class and was winning wherever this sat in the file. */
.ai-quote-parts li.ai-quote-pick {
    padding-bottom: 2px;
}

/* What is behind a tab, on the tab ---------------------------------------- */

/* What is behind a tab, on the tab ----------------------------------------

   THE ALIGNMENT IS THE LAYOUT'S JOB, NOT THE ICON'S

   A FontAwesome glyph sitting inline never lines up with the text beside it:
   it carries its own baseline and its own line-height, and nudging it with
   vertical-align or a top offset only holds until somebody changes the font
   size. Making the tab a flex row instead puts the label and the badge on one
   centre line and keeps them there -- and the gap replaces the badge's left
   margin, which is what was pushing it too far right. */
/* gap:0 on purpose.

   The icon carries margin-right:5px and the count carries margin-left:5px,
   both deliberate and both documented where they are set. The gap was adding
   6px on top of each, so a tab's icon, its label and its tick sat 11px apart
   and stopped reading as one thing -- three items in a row rather than one
   tab with a name. The margins are the spacing; this was the accident. */
#ai-extras-tabs .nav-link {
    display: inline-flex;
    align-items: center;
    gap: 0;
}

.ai-tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;

    /* Off the word, and centred on it.

       THE LIFT HAS BEEN 2px, THEN 0, AND IS 2px AGAIN -- and the reason is the
       same each time: it is set against whatever the label currently is, so it
       has to be reset whenever the label changes. It went to 0 when Archivo
       replaced Cabin Condensed, because the new face sat the circle high of
       the words beside it. The tabs are now 15px UPPERCASE with letter-spacing,
       which has no descenders and a higher optical centre, so the pill wants
       lifting again.

       position: relative stays regardless, so .ai-tab-done below can still set
       its own offset. */
    margin-left: 5px;
    position: relative;
    top: -2px;

    min-width: 18px;
    /* 19, not 18. Centring a glyph in an even-numbered box leaves it half a
       pixel low: the digit's ink is not centred on its own em box, and the
       browser has nowhere to put the remainder. An odd height gives the
       rounding somewhere to land and the number sits true. */
    height: 19px;
    padding: 0 5px;
    border-radius: 10px;
    background: var(--border, #e2e2e2);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    color: var(--text-muted, #6b6b6b);
}

/* On the open tab it belongs to the label, so it takes the label's colour
   rather than sitting there as a grey lump on a highlighted word. */
.nav-link.active .ai-tab-count {
    background: var(--primary, #2e7d5b);
    color: #fff;
}

/* Present rather than counted: no pill, no padding, nothing for it to sit
   off-centre inside. The duotone check carries its own second tone, so the
   ring and the tick read apart where a solid one would be a blob.

   18px because that is the number badge's height. The icon IS its own circle,
   so it has to match the drawn one beside it rather than the 11px digit inside
   it -- sized to the text it replaces, it came out visibly the smaller of the
   two things claiming to be the same kind of mark. */
.ai-tab-done {
    min-width: 0;
    padding: 0;
    background: transparent;
    font-size: 18px;
    /* Its own lift: the pill above is a 19px box with an 11px digit centred
       in it, and this is an 18px glyph sitting on the baseline. The same
       offset would push it too high. */
    top: -1px;
    color: var(--logo-green, #2e7d5b);
}

/* On the open tab it stays green, and the white above it does not apply.

   .nav-link.active .ai-tab-count turns the COUNT pill into a filled primary
   lozenge with a white digit, which is right -- there is a background there
   for white to sit on. This shares that class and then takes the background
   away, so inheriting the white left a white tick on a white tab strip.

   That is why only Proofreading looked wrong: nothing was different about it
   except that it was the tab being looked at. Open Coverage instead and its
   tick vanished too.

   Green rather than the active label's --primary, because the tick is a
   status and not part of the highlight: the script HAS been proofread
   whether or not the tab is open. */
.nav-link.active .ai-tab-done {
    background: transparent;
    color: var(--logo-green, #2bb673);
}
/* The price list on the credits page -------------------------------------- */

.ai-price-intro,
.ai-price-note {
    margin: 0 0 12px;
    font-size: 0.92rem;
    line-height: 1.55;
    color: var(--text-soft, #6b6b6b);
}

.ai-price-note {
    margin: 12px 0 0;
}

.ai-price-table {
    width: 100%;
    border-collapse: collapse;
}

.ai-price-table th {
    padding: 6px 8px;
    border-bottom: 2px solid var(--border, #e2e2e2);
    text-align: left;
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--text-muted, #8a8a8a);
}

.ai-price-table td {
    padding: 10px 8px;
    border-bottom: 1px solid var(--border, #eee);
    vertical-align: top;
}

.ai-price-table tr:last-child td {
    border-bottom: 0;
}

/* The name, then what it is. Stacked rather than in two columns: the
   explanations are a sentence or two and a column of them would be a column of
   wrapped fragments. */
.ai-price-label strong {
    display: block;
    font-size: 0.95rem;
    color: var(--text-dark, #222);
}

.ai-price-what {
    display: block;
    margin-top: 3px;
    font-size: 0.88rem;
    line-height: 1.5;
    color: var(--text-soft, #6b6b6b);
}

th.ai-price-cost,
td.ai-price-cost {
    text-align: right;
    white-space: nowrap;
}

/* "save 10%" under a membership's heading in the credit pack table. */
.ai-price-table th .ai-price-what {
    margin-top: 1px;
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: none;
    letter-spacing: 0;
    color: var(--logo-green, #2e7d5b);
}

.ai-price-fixed {
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--logo-green, #2e7d5b);
}

/* A price that moves with the script's length, as a small ladder rather than a
   sentence: four lengths, four numbers, read down. */
.ai-price-scale {
    display: inline-flex;
    flex-direction: column;
    gap: 2px;
}

.ai-price-step {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: 8px;
    font-size: 0.85rem;
}

.ai-price-pages {
    color: var(--text-muted, #8a8a8a);
}

.ai-price-credits {
    min-width: 2.2em;
    font-weight: 700;
    color: var(--logo-green, #2e7d5b);
}

/* A choice belonging to an optional line ---------------------------------- */

/* Indented to the same 26px as the note above it, so the box, its explanation
   and its one setting read as one block rather than three list rows that
   happen to be adjacent. */
.ai-quote-opt {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 2px 0 6px 26px;
    font-size: 0.9rem;
}

.ai-quote-opt label {
    /* The row inherits space-between from .ai-quote-parts li, which is right
       for a name and a price at opposite ends and wrong here, where the label
       and the dropdown are one thing: it put the dialog's whole width between
       them. The auto margin absorbs that space on the left instead, so the
       pair travels to the right edge together and lines up with the column of
       prices above. */
    margin: 0 0 0 auto;
    color: var(--text-muted, #8a8a8a);
}

.ai-quote-opt select {
    /* Sized to its widest option rather than stretched: growing it would put
       the gap back, on the other side. */
    flex: none;
    max-width: 260px;
    padding: 4px 8px;
    border: 1px solid var(--border, #e6e6e6);
    border-radius: 4px;
    background: #fff;
    font-size: 0.9rem;
    cursor: pointer;
}

/* Off with the line it belongs to. A live dropdown under a dropped item
   invites a choice nothing is going to act on. */
.ai-quote-opt:has(select:disabled) {
    opacity: .55;
}

.ai-quote-opt select:disabled {
    cursor: default;
}


/* The line under the spinner while the AI works -----------------------------

   SweetAlert2 puts its loader above the html block, so this sits below it and
   needs the room. Centred and muted because it is a status, not a question --
   the dialog has no buttons and nothing is being asked. */
/* The spinner, which is ours rather than SweetAlert's -- a wait somebody is
   allowed to leave needs the confirm button, and Swal.showLoading() puts its
   spinner exactly there. See busyDialog() in js/ai-logline.js. */
.ai-busy-spin {
    margin: 4px 0 0;
    text-align: center;
    font-size: 1.6rem;
    color: var(--brand, #d4a017);
}

/* What happens if they close it. Smaller and quieter than the stage line:
   it is read once, at the start, and then never again. */
.ai-busy-note {
    margin: 18px auto 0;
    max-width: 30em;
    font-size: .82rem;
    line-height: 1.5;
    text-align: center;
    color: var(--text-muted, #8a8a8a);
    opacity: .85;
}

.ai-busy-line {
    margin: 14px 0 0;
    text-align: center;
    line-height: 1.45;
    color: var(--text-muted, #8a8a8a);
}

/* The Coverage tab with nothing in it yet ---------------------------------

   Not .ai-tab-empty, which is one grey centred line for a tab that simply has
   no content. This tab has no content because the writer has not bought any,
   which is a different situation and the only place on the card that has to
   argue for itself. Left-aligned and full width: it is read, not glanced at. */
.cv-pitch {
    padding: 6px 2px 4px;
    color: var(--text-soft, #6b6b6b);
    font-size: .93rem;
    line-height: 1.6;
}

.cv-pitch-lead {
    margin: 0 0 16px;
    color: var(--text-main, #2f2f2f);
}

/* What AI Coverage and Analyst Coverage are: no longer two About panels in
   the widget but a circle-question beside its heading, opening a dialog with
   a tab each (Ben, 2026-10-04) -- see openHelp() in js/coverageorder.js. */
.cv-help-btn {
    margin-left: 6px;
    font-size: 0.8em;
    color: var(--text-soft, #8094ae);
    vertical-align: middle;
}

/* Yellow, beside Scores on the member review form (2026-10-04). */
.cv-help-btn--gold {
    color: var(--warning);
    font-size: 1.05em;
}

.cv-help-btn:hover {
    color: var(--brand, #d4a017);
}

/* Nothing written and nothing ordered: the .noneparagraph line other widgets
   show when empty. Gone once a report lands in #aiCoverageOut. */
#aiCoverageOut:not(:empty) ~ .cover-empty {
    display: none;
}

/* One width for both tabs, so switching does not resize the dialog sideways. */
.cv-help-dialog {
    width: min(860px, 92vw);
}

.cv-help-tabs {
    margin-bottom: 16px;
}

.cv-help-pane {
    display: none;
}

.cv-help-pane.active {
    display: block;
}

/* The three analyst products, side by side where there is room and stacked
   where there is not. */
.cv-offers {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 12px;
    margin: 0 0 14px;
}

.cv-offer {
    padding: 12px 14px 4px;
    border: 1px solid var(--border-soft, #e6e6e6);
    border-radius: 6px;
    background: var(--bg-card, #fff);
}

.cv-offer-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.cv-offer-name {
    font-weight: 700;
    color: var(--text-main, #2f2f2f);
}

.cv-offer-price {
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--brand, #d4a017);
    white-space: nowrap;
}

.cv-offer-scope {
    margin: 2px 0 8px;
    font-size: .85rem;
    color: var(--text-muted, #8a8a8a);
}

.cv-offer .cv-pitch-list {
    margin-bottom: 8px;
}

.cv-pitch-note {
    margin: 0;
    font-size: .88rem;
}

/* Which price list this is, and the page surcharge, said once above the cards
   rather than on each. */
.cv-pitch-note--top {
    margin-bottom: 12px;
}

/* The breakdown under a price that carries a page surcharge -- "$129 + $8 for
   133 pages" -- so the total is never a figure nobody explained. */
.cv-offer-extra {
    margin-top: 1px;
    font-size: .82rem;
    color: var(--text-muted, #8a8a8a);
    text-align: right;
}

.cv-pitch-sub {
    margin: 0 0 8px;
    font-weight: 600;
    color: var(--text-main, #2f2f2f);
}

/* The pitch's own body paragraphs. Every other element in here carries a class
   and sets its own margin, so a plain <p> was left with the zero the reset
   gives it and two paragraphs ran together as one block of text.

   :not([class]) rather than a bare `p`, so the lead, the sub, the promo and
   the foot keep the spacing each of them was given. 16px to match the lead,
   which is the gap the rest of the pitch is already measured in. */
.cv-pitch p:not([class]) {
    margin: 0 0 16px;
}

.cv-pitch-list {
    margin: 0 0 16px;
    padding-left: 1.1rem;
    list-style: disc;
}

.cv-pitch-list li {
    margin-bottom: .55rem;
}

.cv-pitch-list b {
    color: var(--text-main, #2f2f2f);
    font-weight: 600;
}

/* The introductory price, which has to be legible as a temporary thing rather
   than read as the price. Tinted rather than shouted: it is good news, and a
   warning colour would make a cheap price look like a problem. */
.cv-pitch-promo {
    margin: 0 0 14px;
    padding: 10px 12px;
    border-left: 3px solid var(--brand, #d4a017);
    background: rgba(212, 160, 23, .07);
    border-radius: 3px;
    font-size: .88rem;
    color: var(--text-main, #2f2f2f);
}

.cv-pitch-promo i {
    margin-right: 6px;
    color: var(--brand, #d4a017);
}

/* The last word is about keeping them, so it sits apart from the list of what
   one contains. */
.cv-pitch-foot {
    margin: 0;
    padding-top: 12px;
    border-top: 1px solid var(--border-soft, #e6e6e6);
    font-size: .88rem;
}

/* Coverage -----------------------------------------------------------------

   A reader's report. Longer than anything else here and read differently: the
   verdict is glanced at, the prose once, and the quotations are what a writer
   comes back to -- so each one stays beside the paragraph that earned it. */

.cv-verdict {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 16px;
    border-radius: 8px;
    margin-bottom: 14px;
}

.cv-verdict-word {
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.cv-verdict-score {
    font-size: 1.5rem;
    font-weight: 700;
    white-space: nowrap;
}

/* The verdict and its score on the SHUT panel.

   The one thing anybody reads before deciding which report to open, so it is
   sized to be read at a glance down a stack of three rather than to sit
   politely inside the grey line it shares. Well above .ai-panel-meta's .82rem
   and above the title's .95rem too -- on this panel the judgement outranks the
   word 'Coverage', which is only there to say what kind of thing it is.

   The date that used to sit beside it is in the title now, and the draft is
   gone altogether, so this has the line largely to itself. */
.cv-meta-lead {
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.2;
}

/* Five, and they have to read as a ladder rather than five unrelated states:
   grey at the bottom, through amber, to green. */
.cv-meta-lead--recommend       { color: #17683a; }
.cv-meta-lead--consider-strong { color: #4a7a2c; }
.cv-meta-lead--consider        { color: #7a5c00; }
.cv-meta-lead--consider-weak   { color: #8a6a2f; }
.cv-meta-lead--pass            { color: #5b5b5b; }

/* The five answers mean different things and should not look alike. The two
   qualified Considers sit either side of the plain one rather than beside it:
   a Strong Consider is nearer a Recommend than it is to a Weak one. */
.cv-verdict--recommend       { background: #e6f4ea; color: #17683a; }
.cv-verdict--consider-strong { background: #eef4e4; color: #4a7a2c; }
.cv-verdict--consider        { background: #fdf3d8; color: #7a5c00; }
.cv-verdict--consider-weak   { background: #f8f1e2; color: #8a6a2f; }
.cv-verdict--pass            { background: #f2f2f2; color: #5b5b5b; }

.cv-cat-of {
    font-size: .7em;
    font-weight: 500;
    opacity: .65;
}

/* Form, genre and length. Sized with the paragraphs above them now that they
   live in the Overview box -- at .85rem they read as a caption under four
   sections of 1.1rem prose, which is the one thing they are not. */
.cv-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 20px;
    margin-bottom: 10px;
    font-size: 1.05rem;
    line-height: 1.5;
    color: var(--text-soft, #555);
}

/* The label, quieter than the value it introduces -- the reverse of how it
   read when the whole line was grey. */
.cv-fact b {
    color: var(--text-muted, #8a8a8a);
    font-weight: 600;
    margin-right: 5px;
}

/* What the report says before it starts scoring: what this script IS, at four
   lengths. Everything below it is about how well it is written.

   Slate, not gold. The first version of this was warm cream with a gold left
   edge, which is exactly what .cv-standout wears -- so the box that says what
   the script IS and the box that says what the writer is BEST at read as the
   same kind of thing, sitting one above the other. Gold is spoken for; this is
   a cool grey-blue, distinct from the standout above it, from the blue
   .cv-format note, and from the near-white boxes further down. */
.cv-overview-box {
    margin: 0 0 18px;
    padding: 12px 16px 14px;
    border: 1px solid #d9dfe4;
    border-left: 4px solid #5b7c93;
    border-radius: 6px;
    background: #f6f8fa;
}

/* Ruled off, so the title reads as the box's own and not as a label on the
   logline directly under it. */
.cv-overview-title {
    margin-bottom: 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid #e1e7eb;
}

.cv-overview-title .cv-cat-name i {
    margin-right: 7px;
    color: #5b7c93;
}

/* The headings inside it take the box's colour rather than the site gold, so
   the block reads as one thing. */
.cv-overview-box .cv-box-head i {
    color: #5b7c93;
}

/* The form, genre and length chips, now the last thing in the box and sitting
   on its tint. Whatever bottom margin they carried loose on the page is the
   box's padding now. */
.cv-overview-box .cv-facts {
    margin-bottom: 0;
}

/* The label on a box. Big enough to be read rather than squinted at, and no
   longer uppercase -- at this size the tracking that made small caps legible
   turns into a stretched-out banner competing with the category headings. */
.cv-box-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0 0 7px;
    font-size: 1.1rem;
    font-weight: 700;
    letter-spacing: 0;
    color: var(--color-text-body);
}

/* Fixed width so the headings line up with each other down the report, and
   quieter than the words it introduces. */
.cv-box-head i {
    flex: 0 0 1.1em;
    color: var(--brand, #d4a017);
    font-size: .95em;
}

.cv-box-head + .cv-logline,
.cv-box-head + .cv-overview {
    margin-top: 0;
}

/* Every heading after the first wants space above it, away from the paragraph
   it follows. The first one is already clear of the title's rule. */
.cv-overview-title ~ .cv-box-head {
    margin-top: 14px;
}

.cv-overview-title + .cv-box-head {
    margin-top: 0;
}

.cv-logline {
    margin: 0 0 14px;
    font-size: 1.1rem;
    font-style: italic;
    line-height: 1.5;
    color: var(--text-dark, #333);
}

/* The same gap under it as under the logline, because it is no longer the last
   thing in the box -- the comparables and the audience follow it now, and their
   headings were sitting straight against the paragraph above.

   Whichever paragraph ends up last loses the margin below, so the box does not
   carry a gap its padding already provides. :last-child rather than a class,
   because which one is last depends on what the report returned. */
/* No font-size. It was 1.1rem, set when the body face was condensed and the
   overview wanted lifting off it; in the wider face that made the report's
   opening paragraphs the largest prose on the page. Inheriting puts them back
   with the rest of the report, which is where a summary belongs -- and means
   one place to change the report's reading size rather than two. */
.cv-overview {
    margin: 0 0 14px;
    line-height: 1.55;
}

.cv-overview-box > p:last-child {
    margin-bottom: 0;
}

/* All seven scores at a glance, above the seven that explain themselves.

   Boxed like the Overview, and neutral: this one is a table of contents for
   the section under it rather than a thing with an argument of its own, so it
   takes the plain near-white and lets the bars carry all the colour. */
.cv-summary {
    margin: 0 0 18px;
    padding: 12px 16px 14px;
    border: 1px solid var(--border, #e6e6e6);
    border-radius: 6px;
    background: #fcfcfc;
}

.cv-summary-title {
    margin-bottom: 10px;
    padding-bottom: 8px;
    border-bottom: 1px solid #ededed;
}

.cv-summary-title .cv-cat-name i {
    margin-right: 7px;
    color: var(--text-muted, #8a8a8a);
}

/* Three columns, so the names end together and every bar starts on the same
   line -- which is the whole point of putting them in a column. auto for the
   name rather than a fixed width: the longest is Marketability and it should
   set the measure rather than a number somebody guessed. */
.cv-sum-grid {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 7px 12px;
}

/* Each row is three cells of the same grid rather than a box of its own, or
   the columns could not line up across rows. */
.cv-sum-row {
    display: contents;
}

.cv-sum-name {
    font-size: .95rem;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: var(--text-soft, #555);
    white-space: nowrap;
}

.cv-sum-bar {
    display: block;
    height: 9px;
    border-radius: 5px;
    background: #ececec;
    overflow: hidden;
}

.cv-sum-bar > span {
    display: block;
    height: 100%;
    border-radius: 5px;
}

.cv-sum-score {
    font-size: 1.1rem;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    text-align: right;
}

/* The same bands as the cards below, from the same coverageBand(). */
.cv-sum-row--broken .cv-sum-bar > span { background: #c0392b; }
.cv-sum-row--weak   .cv-sum-bar > span { background: #e07b39; }
.cv-sum-row--fair   .cv-sum-bar > span { background: #c9a84c; }
.cv-sum-row--good   .cv-sum-bar > span { background: #4a9d5f; }
.cv-sum-row--strong .cv-sum-bar > span { background: #1f7a4d; }
.cv-sum-row--none   .cv-sum-bar > span { background: #ccc; }

.cv-sum-row--broken .cv-sum-score { color: #c0392b; }
.cv-sum-row--weak   .cv-sum-score { color: #e07b39; }
.cv-sum-row--fair   .cv-sum-score { color: #a8862c; }
.cv-sum-row--good   .cv-sum-score { color: #4a9d5f; }
.cv-sum-row--strong .cv-sum-score { color: #1f7a4d; }
.cv-sum-row--none   .cv-sum-score { color: #999; }

/* Two columns on anything roomy: seven rows is a lot of vertical space for a
   thing whose whole job is to save scrolling. */
@media (min-width: 620px) {
    .cv-sum-grid {
        grid-template-columns: auto 1fr auto auto 1fr auto;
        column-gap: 12px;
    }
}

/* The scoreboard, one category to a row.

   It was three across, which was chosen so the eye could compare scores rather
   than read them in order -- but there are seven categories, and seven does not
   divide by three. The last one sat alone on a line looking like an afterthought
   at whatever width the grid gave it, and the assessments underneath had grown
   to a paragraph each, which is not something to read in a 300px column.

   Full width gives the prose a sensible measure and puts the seven scores in a
   single vertical line down the left edge, which compares them better than three
   columns ever did. */
.cv-cats {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
    margin-bottom: 18px;
}

.cv-cat {
    padding: 12px 14px;
    border: 1px solid var(--border, #e6e6e6);
    border-left-width: 4px;
    border-radius: 6px;
    background: #fcfcfc;
}

.cv-cat-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

/* Full width made these the headings of the report rather than labels on a
   card in a grid, so they are sized as headings. The letter-spacing comes down
   with the size going up: tracking that opens up small uppercase type starts
   to look thin and stretched once the type is this big. */
.cv-cat-name {
    font-weight: 700;
    font-size: 1.2rem;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--text-soft, #555);
}

/* Kept clearly above the name beside it. The score is the thing being read
   down the column; the category is what it is about. */
.cv-cat-score {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
}

.cv-bar {
    height: 4px;
    margin: 8px 0 10px;
    border-radius: 2px;
    background: #ececec;
    overflow: hidden;
}

.cv-bar span {
    display: block;
    height: 100%;
}

/* The bands the prompt defines, so what a writer sees and what the model was
   told cannot drift apart. */
.cv-cat--broken { border-left-color: #c0392b; }
.cv-cat--weak   { border-left-color: #e07b39; }
.cv-cat--fair   { border-left-color: #c9a84c; }
.cv-cat--good   { border-left-color: #4a9d5f; }
.cv-cat--strong { border-left-color: #1f7a4d; }
.cv-cat--none   { border-left-color: #ccc; }

.cv-cat--broken .cv-bar span { background: #c0392b; }
.cv-cat--weak   .cv-bar span { background: #e07b39; }
.cv-cat--fair   .cv-bar span { background: #c9a84c; }
.cv-cat--good   .cv-bar span { background: #4a9d5f; }
.cv-cat--strong .cv-bar span { background: #1f7a4d; }

/* The argument for the score, which is the part a writer actually reads --
   five to eight sentences of it. Sized to be read rather than scanned. */
.cv-cat-text {
    margin: 0;
    font-size: 1.1rem;
    line-height: 1.55;
    color: var(--text-soft, #555);
}

/* A partner's percentile under its score (format 1.1, Ben 2026-10-08). */
.cv-percentile {
    margin: 4px 0 8px;
    font-size: 0.95rem;
    color: var(--text-muted, #8094ae);
}

.cv-percentile i {
    margin-right: 4px;
    color: var(--gold, #c9a84c);
}

/* The evidence, three across.

   The prompt asks for two or three quotations per category, so three is the
   real maximum rather than an arbitrary one. flex-grow lets two fill the row
   between them rather than leaving a third of it blank, and the min-width drops
   them to two-up and then one-up on a narrow card without a media query --
   these appear inside a dashboard panel whose width is not the window's. */
.cv-evidences {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 10px;
    align-items: stretch;
}

.cv-evidences .cv-evidence {
    flex: 1 1 calc(33.333% - 7px);
    min-width: 220px;
    margin: 0;
}

/* The line from the script. Monospaced, because it is a quotation from a
   document and not the report's own voice. */
.cv-evidence {
    margin: 10px 0 0;
    padding: 8px 10px;
    border-left: 3px solid var(--border, #ddd);
    background: #fff;
    font-family: ui-monospace, "Courier New", monospace;
    font-size: .82rem;
    line-height: 1.45;
    color: var(--text-dark, #444);
}

.cv-evidence cite {
    display: block;
    margin-top: 4px;
    font-family: inherit;
    font-style: normal;
    font-size: .95em;
    color: var(--text-muted, #999);
}

.cv-columns {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 14px;
    margin-bottom: 18px;
}

.cv-list h4 {
    margin: 0 0 8px;
    font-size: .82rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-soft, #555);
}

.cv-list ul {
    margin: 0;
    padding-left: 18px;
}

.cv-list li {
    margin-bottom: 7px;
    font-size: .93rem;
    line-height: 1.5;
}

.cv-list--good li::marker { color: #4a9d5f; }
.cv-list--bad li::marker  { color: #e07b39; }

/* The one thing a writer should leave with. Everything above it is the
   argument for this.

   It was --bg-light, which is a hair off the page behind it -- so the most
   actionable sentence in the report sat in a box you could barely see. Coral,
   which is --primary and already the colour of the step areas in the plan
   underneath: this is the imperative, and the plan is how to carry it out. */
.cv-note {
    padding: 12px 16px;
    border: 1px solid #f0d2cd;
    border-left: 4px solid var(--primary, #e85347);
    border-radius: 8px;
    background: #fdf2f0;
    margin-bottom: 16px;
}

.cv-note .cv-box-head i {
    color: var(--primary, #e85347);
}

/* Its heading is a .cv-box-head like every other box now. There is no
   '.cv-note h4' rule any more ON PURPOSE: an element selector inside a class
   beats a bare class, so it would have quietly won every argument with
   .cv-box-head and kept this one heading small and uppercase while the rest
   grew. Same reason .cv-plan h4 is gone. */
.cv-note-text {
    margin: 0;
    font-size: 1.02rem;
    line-height: 1.55;
}

/* The three closing notes as a group. It has never had a rule of its own --
   the paragraphs it used to hold carried their own spacing -- and the boxes now
   inside it want a gap above them, away from the What To Do Next list. */
.cv-tails {
    margin-top: 18px;
}

/* The closing note. Its own class rather than a second .cv-note rule -- there
   was one of those for a while, and two rules for one name is how a box ends
   up with whichever background happened to be written last. */
.cv-aside {
    margin: 0 0 10px;
    padding: 12px 14px;
    border: 1px solid var(--border, #e6e6e6);
    border-radius: 6px;
    background: #fcfcfc;
}

.cv-aside:last-child {
    margin-bottom: 0;
}

.cv-aside-text {
    margin: 0;
    font-size: 1.02rem;
    line-height: 1.5;
    color: var(--text-soft, #555);
}

/* The one that admits a limit. Tinted rather than greyed: it is the most
   honest paragraph in the report and should not look like the least. */
.cv-aside--caveat {
    border-color: #e6dcc0;
    background: #fdfaf2;
}

.cv-aside--caveat .cv-box-head i {
    color: #b08a2e;
}

/* The moments worth stopping on, in page order. Read with the script open
   beside it, which is why the page number is the thing that stands out. */
.cv-scenes {
    margin-bottom: 18px;
}

.cv-scenes h4,

.cv-scene {
    display: flex;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border, #eee);
}

.cv-scene:last-child {
    border-bottom: 0;
}

.cv-scene-page {
    flex: none;
    width: 46px;
    font-family: ui-monospace, "Courier New", monospace;
    font-size: .82rem;
    color: var(--text-muted, #999);
    padding-top: 2px;
}

.cv-scene-body {
    font-size: .93rem;
    line-height: 1.5;
}

/* The plan. Numbered, and in the order the work should be done -- structural
   before line, because a line polished in a scene that gets cut is wasted. */
.cv-plan {
    padding: 14px 16px;
    border: 1px solid var(--border, #e6e6e6);
    border-radius: 8px;
    background: #fcfcfc;
    margin-bottom: 16px;
}

.cv-plan ol {
    margin: 0;
    padding-left: 20px;
}

.cv-plan li {
    margin-bottom: 14px;
}

.cv-plan li:last-child {
    margin-bottom: 0;
}

.cv-step-head {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: 4px;
}

/* Which part of the script this job is about. */
.cv-step-area {
    font-size: .88rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--primary, #e85347);
}

/* What it costs to do, which is half of whether it gets done. Sized with the
   area beside it so the pair reads as one line rather than a label and a
   footnote. */
.cv-step-effort {
    font-size: .86rem;
    padding: 2px 9px;
    border-radius: 10px;
    background: var(--bg-light, #f0f0f0);
    color: var(--text-muted, #777);
}

.cv-step-change {
    margin: 0 0 4px;
    font-weight: 600;
    line-height: 1.5;
}

.cv-step-why,
.cv-step-where {
    margin: 0 0 3px;
    font-size: .89rem;
    line-height: 1.5;
    color: var(--text-soft, #666);
}

.cv-step-where {
    font-family: ui-monospace, "Courier New", monospace;
    font-size: .8rem;
    color: var(--text-muted, #999);
}

/* The best thing about the script -------------------------------------------

   Under the verdict, because a writer opening a report that says Consider is
   braced for what is wrong and will not go looking for what is right. Scores
   between four and seven all look alike at a glance; this is the sentence that
   says which instinct to trust through the rewrite. */
.cv-standout {
    padding: 12px 16px;
    margin-bottom: 14px;
    border: 1px solid #d8c88a;
    border-left: 4px solid var(--gold, #c9a84c);
    border-radius: 8px;
    background: #fdfaf0;
}

.cv-standout-head {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: #8a6d1f;
    margin-bottom: 6px;
}

.cv-standout-cat {
    padding: 1px 8px;
    border-radius: 10px;
    background: var(--gold, #c9a84c);
    color: #3a2f0b;
    letter-spacing: .04em;
}

.cv-standout-claim {
    margin: 0;
    font-size: 1rem;
    line-height: 1.55;
    color: var(--text-dark, #333);
}

/* And the card it belongs to, so the badge and the sentence agree. */
.cv-cat--best {
    border-color: #d8c88a;
    border-left-color: var(--gold, #c9a84c);
    background: #fffdf6;
}

.cv-cat--best .cv-cat-name i {
    color: var(--gold, #c9a84c);
}

/* What the report was read from, and when ----------------------------------

   Above the verdict. Coverage is an opinion about a particular set of pages on
   a particular day, and a report that does not say which pages is one nobody
   can argue with -- or trust six months later, having forgotten which draft
   they submitted. */
/* What was read, and when. It was .82rem, which is a footnote size for a line
   carrying the draft, the page count and the format the report judged it as --
   the three facts that decide whether the rest of it applies to the script the
   writer has now. */
.cv-read {
    margin: 0 0 12px;
    font-size: .98rem;
    line-height: 1.5;
    color: var(--text-muted, #8a8a8a);
}

.cv-read b {
    color: var(--text-soft, #666);
}

/* Still worth reading, and must not pretend the pages have not moved. */
.cv-read--stale {
    padding: 8px 10px;
    border-left: 3px solid var(--warning, #e0a800);
    background: #fffaf0;
    border-radius: 4px;
}

.cv-read-warn {
    display: block;
    margin-top: 5px;
    font-size: .95rem;
    color: #8a6d1f;
    font-weight: 600;
}

.cv-read-warn i {
    margin-right: 5px;
}

/* Who wrote it -------------------------------------------------------------

   The difference between a machine's opinion and one a reader has stood behind
   is the whole of what a human review is sold as, so a writer must never have
   to guess which they are looking at. */
.cv-by {
    display: inline-block;
    margin-right: 8px;
    padding: 1px 8px;
    border-radius: 10px;
    background: var(--bg-light, #f0f0f0);
    color: var(--text-muted, #777);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.cv-by--human {
    background: #e6f4ea;
    color: #17683a;
}

.cv-by--waiting {
    background: #fdf3d8;
    color: #7a5c00;
}

/* The author's way to be rid of a report -----------------------------------

   At the foot of the report rather than on its header line: a stack of three
   all carry one, and a trash can beside a collapsed title is a click away from
   deleting the wrong one. */
/* The author's controls, above the report ----------------------------------

   A header rather than a footer, so the border and the spacing are on the
   underside: this row introduces the report rather than closing it off.

   A flex row rather than text-align, because the share control stops being
   a button and becomes a row of its own once there is a link in it. */
/* The AI Extras panes, and the bottom padding they are allowed only while one
   of them is open.

   This was an inline padding:0 10px 10px on the container. With every tab shut
   -- which switchAiTab() now allows -- the panes contribute no height and that
   bottom 10px was the whole of what was left: a bare strip hanging under the
   tab bar with nothing in it. The Script Elements widget never had the problem
   because its container carries no bottom padding at all.

   :has() rather than a class the script toggles, because the question is about
   what is in the markup and the markup already answers it. That also covers
   the state the server renders, without the page having to be told twice. */
.ai-extras-panes {
    padding: 0 10px 10px;
}

/* No bottom padding while the widget is shut.

   That 10px is for the panes; with none of them open it is added to the 10px
   the hint line already carries below itself, and the line sits 10 above / 20
   below instead of centred. The Script Elements container has no bottom
   padding at all, which is why it looked right and this did not.

   This rule existed before the hint line did, to stop a bare strip hanging
   under the tab bar, and was then written as :not(:has(> .tabs-hint)) so it
   would stand down once there was something in that space. That was wrong on
   its own terms -- :has() asks whether the element is PRESENT, and the hint is
   always in the markup and merely hidden -- so the rule could never fire. It
   is the plain question again, which is the one that was wanted both times. */
.ai-extras-panes:not(:has(> .tab-pane.active)) {
    padding-bottom: 0;
}

/* ---- the closed state, and how anybody finds out about it --------------- */

/* The line that only exists while every tab is shut.

   Hidden by default and revealed by the absence of an open pane, so nothing
   has to tell it -- the same :has() question the padding above asks, and it
   covers the state the server renders as well as the one a click produces.

   It is here to make the closed widget legible: a head, a row of tabs and
   nothing else reads as something that failed to load. It cannot teach the
   CLOSING half, because nobody sees it until they have already closed
   something. The caret below is what does that. */
/* 16px, not the 13px it was: at that size, in grey, it read as a footnote and
   was missed -- it is the only thing the closed widget has to say. */
.tabs-hint {
    display: none;
    margin: 0;
    padding: 12px 2px;
    font-size: 16px;
    color: var(--text-soft, #6a6a6a);
}

.ai-extras-panes:not(:has(> .tab-pane.active)) > .tabs-hint,
.elements-panes:not(:has(> .tab-pane.active)) > .tabs-hint,
.media-panes:not(:has(> .tab-pane.active)) > .tabs-hint {
    display: block;
}

/* A caret on the open tab, pointing at the thing it will fold away.

   This is the half of the gesture nobody would guess at. A tab bar says
   'these are the choices'; it does not say 'and the one you are on will close
   if you press it again', and a title attribute only says so to somebody who
   already hovered and waited.

   A character rather than a Font Awesome glyph in ::after: the kit is loaded
   by name and weight and a pseudo-element that guesses either of those wrong
   renders a blank box. U+25B4 is in every font that will ever draw this page. */
/* The media widget is drawn three times on the site -- script, idea, project --
   so its strips are matched by a suffix rather than named one at a time. */
#ai-extras-tabs .nav-link.active::after,
#script-elements-tabs .nav-link.active::after,
#project-series-tabs .nav-link.active::after,
ul[id$="-media-tabs"] .nav-link.active::after {
    content: "▲";
    margin-left: 6px;
    font-size: .75em;
    opacity: .8;
}

/* The bottom padding stays now, in every state.

   It was dropped when no tab was open, because what was left was a bare strip
   under the tab bar. The hint line lives in that space now, so the padding is
   the room it sits in rather than a gap. */

/* The line at the top of a panel that lets its contents be thrown away.

   One rule for all five -- coverage aside, which shares its row with Share
   this report -- so the bin is in the same place and the same shape whichever
   panel somebody is looking at.

   Right-aligned: it is the least likely thing anybody wants from the panel, so
   it sits away from the left margin where the eye lands, while staying on the
   first line where it can be found at all. The rule below it separates it from
   the content it governs. */
.ai-delete-row {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--border, #eee);
}

.cv-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 18px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border, #eee);
}

/* The offer ----------------------------------------------------------------

   Deliberately quieter than a primary button. Publishing coverage is a
   thing a writer should do on purpose, having decided to, and not because
   the brightest thing on the report invited them to.

   THE .ps- HOOK ON EVERY RULE FROM HERE DOWN

   The Public Link at the foot of a script's summary card is the same control
   one level up: it publishes the whole shop window rather than one report,
   and it should be indistinguishable to look at, because a writer who has met
   one has met both.

   Two hooks on one ruleset rather than a second copy of it in
   css/dashboard.css, which is what this was first -- ninety lines of nearly
   the same declarations, and the first change to either would have been the
   moment the two stopped matching.

   Separate CLASS NAMES rather than the same one, though, and that is not
   cosmetic: js/ai-logline.js matches .cv-share-copy and .cv-share-revoke to
   decide what to post where. Sharing the class would mean revoking a public
   link posted to classes/shareCoverage.php with a handle it has never heard
   of. The look is shared here; the behaviour is not shared anywhere. */
.cv-full-link,
.cv-share,
.cv-export,
.cv-pdf,
.cv-print,
.ps-share {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 12px;
    border: 1px solid var(--border, #e6e6e6);
    border-radius: 6px;
    background: #fff;
    color: var(--text-soft, #555);
    font-size: .82rem;
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease;
}

.cv-full-link:hover,
.cv-share:hover,
.cv-export:hover,
.cv-pdf:hover,
.cv-print:hover,
.ps-share:hover {
    color: #17683a;
    border-color: #17683a;
}

/* While a PDF is being made or the print copy is loading. The first PDF of a
   report takes a few seconds, and a button that does nothing visible for that
   long gets pressed again. */
.cv-pdf.is-busy,
.cv-print.is-busy {
    opacity: .6;
    cursor: progress;
    pointer-events: none;
}

/* An <a>, so the underline a link would otherwise get is taken off. */
.cv-export,
.cv-export:hover,
.cv-full-link,
.cv-full-link:hover { text-decoration: none; }

/* A partner's report: whose it is, before anything it says -----------------

   Their logo and name on the left, linking to their site; "Read the full
   coverage" pushed to the right, because the full report is on their site and
   that is the one thing here that leaves ours. The logo is our own saved copy
   (usermedia/partners/), held to the height of a line of the title so no
   partner's artwork can dominate the report it credits. */
.cv-partner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 14px;
    margin-bottom: 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border, #eee);
}

.cv-partner-logo {
    display: block;
    max-height: 40px;
    max-width: 160px;
    width: auto;
    height: auto;
}

.cv-partner-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.cv-partner-name {
    font-weight: 600;
    color: inherit;
    text-decoration: none;
}

.cv-partner-name:hover { text-decoration: underline; }

.cv-partner-verified {
    font-size: .8rem;
    color: #17683a;
}

.cv-full-link { margin-left: auto; }

@media (max-width: 620px) {
    .cv-full-link { margin-left: 0; }
}

/* Share and Export, together on the left of the row. Grows so a published
   link inside it can still take the width it takes on its own. */
.cv-actions-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    flex: 1 1 auto;
}

/* The link, once it exists -------------------------------------------------

   Tinted, because a report with a public address is in a different state
   from one without and the writer should be able to see that from across
   the page rather than by reading a button. Green: the same colour the
   Recommend verdict uses, and the same thing it means here -- live. */
.cv-shared,
.ps-shared {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    flex: 1 1 320px;
    padding: 7px 10px;
    border: 1px solid #cfe4d6;
    border-radius: 6px;
    background: #f2f9f4;
}

.cv-shared-icon,
.ps-shared-icon { color: #17683a; }

/* An input rather than text, so it can be selected on a phone where the
   copy button is not always how somebody chooses to do it. Styled to look
   like the line of text it is. */
.cv-share-url,
.ps-share-url {
    flex: 1 1 200px;
    min-width: 0;
    padding: 3px 6px;
    border: 1px solid #dfece3;
    border-radius: 4px;
    background: #fff;
    color: var(--text-soft, #555);
    font-family: ui-monospace, "Courier New", monospace;
    font-size: .78rem;
}

.cv-share-copy,
.cv-share-revoke,
.ps-share-copy,
.ps-share-revoke {
    padding: 4px 9px;
    border: 1px solid #cfe4d6;
    border-radius: 5px;
    background: #fff;
    color: var(--text-soft, #666);
    font-size: .82rem;
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease;
}

.cv-share-copy:hover,
.ps-share-copy:hover   { color: #17683a; border-color: #17683a; }
.cv-share-revoke:hover,
.ps-share-revoke:hover { color: var(--danger, #e85347); border-color: var(--danger, #e85347); }

/* The first question anybody who sends a link asks. */
.cv-share-views,
.ps-share-views {
    font-size: .78rem;
    color: var(--text-muted, #8a8a8a);
    white-space: nowrap;
}

@media (max-width: 620px) {
    .cv-actions { justify-content: flex-start; }
    .cv-shared,
    .ps-shared  { flex: 1 1 100%; }
}

.cv-delete {
    padding: 5px 12px;
    border: 1px solid var(--border, #e6e6e6);
    border-radius: 6px;
    background: #fff;
    color: var(--text-muted, #999);
    font-size: .82rem;
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease;
}

.cv-delete:hover {
    color: var(--danger, #e85347);
    border-color: var(--danger, #e85347);
}

/* When the pages and the filing disagree -----------------------------------

   Above the verdict and the standout, because it changes how everything under
   it should be read. A report that judged a feature as a pilot is not wrong so
   much as answering a different question. */
.cv-format {
    display: flex;
    gap: 10px;
    padding: 12px 14px;
    margin-bottom: 14px;
    border: 1px solid #cfe0ee;
    border-left: 4px solid #3d7ea6;
    border-radius: 8px;
    background: #f4fafd;
    font-size: .93rem;
    line-height: 1.55;
}

.cv-format i {
    color: #3d7ea6;
    padding-top: 3px;
}

.cv-format b {
    display: block;
    margin-bottom: 3px;
    font-size: .74rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #2c6183;
}

/* Proofreading ---------------------------------------------------------------

   A report of errors rather than an argument, so it is drawn as a list and not
   as prose. The volume is the whole design problem: four hundred findings is a
   wall, and the tabs above these rules are what turn it into five short lists. */

.pr-total {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0 0 14px;
}

.pr-total-n {
    font-size: 1.9rem;
    font-weight: 700;
    line-height: 1;
    color: var(--color-text-body);
}

.pr-total-w {
    font-size: 1rem;
    color: var(--text-muted, #8a8a8a);
}

/* Pages that were not read. Said near the top and coloured like a warning,
   because a writer who believes the whole script was checked has been misled by
   an omission. */
.pr-gap {
    display: flex;
    gap: 10px;
    margin: 0 0 14px;
    padding: 11px 13px;
    border: 1px solid #e6dcc0;
    border-left: 4px solid #d4a017;
    border-radius: 6px;
    background: #fdfaf2;
    font-size: 1rem;
    line-height: 1.5;
}

.pr-gap i { color: #b08a2e; }

.pr-tabs {
    margin-bottom: 10px;
}

.pr-tabs .nav-link i {
    margin-right: 6px;
    opacity: .7;
}

.pr-blurb {
    margin: 0 0 12px;
    font-size: .95rem;
    line-height: 1.5;
    color: var(--text-muted, #8a8a8a);
}

/* One finding. The page number runs down the left because that is what a writer
   scans to find their place; the quotation gets the weight because it is the
   thing being talked about. */
/* Padded on the sides as well, so a tinted row has an edge to sit inside
   rather than running into the panel wall. Every finding carries it, handled
   or not, or the tinted ones would sit 8px right of the rest. */
.pr-find {
    display: flex;
    gap: 12px;
    padding: 10px 8px;
    border-top: 1px solid #f0f0f0;
}

.pr-find:first-of-type { border-top: none; }

.pr-find-where {
    flex: 0 0 62px;
    text-align: right;
    padding-top: 2px;
}

.pr-find-page {
    display: block;
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-text-body);
}

.pr-find-el {
    display: block;
    font-size: .72rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-muted, #aaa);
}

.pr-find-body { flex: 1 1 auto; min-width: 0; }

/* Monospaced for the same reason the coverage evidence is: it is a quotation
   from a document, not the report's own voice. */
.pr-find-quote {
    margin: 0 0 5px;
    padding: 6px 10px;
    border-left: 3px solid #e0e0e0;
    background: #fafafa;
    font-family: ui-monospace, "Courier New", monospace;
    font-size: .88rem;
    line-height: 1.45;
    color: var(--text-dark, #444);
    overflow-wrap: anywhere;
}

.pr-find-note {
    margin: 0;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--text-soft, #555);
}

.pr-find-fix {
    display: flex;
    gap: 7px;
    margin: 5px 0 0;
    font-size: 1rem;
    line-height: 1.5;
    color: #1f7a4d;
}

.pr-find-fix i { padding-top: 4px; opacity: .8; }
.pr-find-fix span { font-weight: 600; }

/* Severity, on the quotation's edge only. A whole row tinted red for a missing
   comma reads as an emergency. */
.pr-find--high .pr-find-quote   { border-left-color: #c0392b; }
.pr-find--medium .pr-find-quote { border-left-color: #e0a800; }
.pr-find--low .pr-find-quote    { border-left-color: #d0d0d0; }

/* The icon on an AI Extras tab. Quieter than the label -- it is there to make
   the row scannable, not to compete with the word it sits beside. Comes up to
   full strength on the open tab, where it is part of the highlight. */
/* Close to the label. The icon and the word are one thing -- a gap wide enough
   to read as a separator makes the icon look like it belongs to the tab before
   it. */
.ai-tab-icon {
    margin-right: 5px;
    opacity: .55;
}

.nav-link.active .ai-tab-icon {
    opacity: 1;
}

/* The AI Extras tab row, and the tabs inside a proofreading report -----------

   Four tabs with an icon and a badge each, at the site's 18px nav-link with
   12px/16px padding, is a wide row -- and the AI Extras widget sits inside a
   card inside a column, so it runs out of width long before the window does.
   These are tighter than the site default on purpose, and tighter again as the
   window narrows, because the alternative is a tab row that wraps to two lines
   and stops reading as a row at all. */
#ai-extras-tabs {
    gap: 0;
    flex-wrap: wrap;
}

#ai-extras-tabs .nav-link,
.pr-tabs .nav-link {
    /* NO font-size AND NO letter-spacing HERE ANY MORE.
     *
     * A tab should look like a tab wherever it is, so these take the site
     * default from .nav-tabs .nav-link -- 16px, uppercase, .04em -- rather
     * than carrying a size of their own. This rule used to set 15px, from
     * back when it was the only way to keep the row on one line.
     *
     * PADDING IS THE LEVER NOW, and it is the right one: it is the part of a
     * tab nobody reads. 10px 9px is already tighter than the site's 12px 16px,
     * and the two media queries below tighten it further before they touch the
     * type at all.
     *
     * This row is the tightest on the site -- up to seven tabs inside a card
     * column: Loglines, Breakdown, Coverage, Proofread, Synopsis, Pitch,
     * Poster -- and uppercase is wider than the sentence case it replaced. If
     * it ever wraps on a size that matters, take the padding here before the
     * size: a row of smaller type is a row that no longer matches every other
     * tab row on the site, which is the thing this change was for.
     *
     * LESS UNDERNEATH THAN ABOVE. Uppercase has no descenders, so the space
     * below a label measures larger than the same number above it -- the row
     * looked bottom-heavy and the active underline sat further from the word
     * it belongs to than it should. 6px under against 10 over is level to the
     * eye rather than on paper.
     */
    padding: 10px 9px 6px 9px;
    /* NO line-height here any more. It was this row's own fix for labels
     * sitting at two heights when some tabs carry a badge and some do not --
     * and it worked, and left the Script Elements row with the identical bug,
     * because that row uses the identical badge classes. It is on
     * .nav-tabs .nav-link in css/dashboard.css now, where every tab strip
     * gets it. That rule carries the full explanation. */
}

.pr-tabs {
    gap: 0;
    flex-wrap: wrap;
}

@media (max-width: 900px) {

    /* Padding only. The type stays at the site's 15px here -- a tab row on a
       900px window should still look like every other tab row on the site,
       and the padding has not run out yet. The bottom keeps its 4px less than
       the top, for the same reason it has it at full width. */
    #ai-extras-tabs .nav-link,
    .pr-tabs .nav-link {
        padding: 9px 7px 5px 7px;
    }

    .ai-tab-icon {
        margin-right: 4px;
    }

    .ai-tab-count {
        margin-left: 4px;
    }
}

/* Narrower still: the icon is doing the identifying by now, and the labels are
   what has to give. */
@media (max-width: 620px) {

    /* Here the type does give, because the padding has nothing left. Seven
       uppercase labels do not fit a phone at the site's 15px however tight the
       boxes are, and a wrapped row of three lines is worse than a smaller one.
       The letter-spacing goes with it: at this size it is width, not
       legibility. One step down, not two -- 13px would be smaller than the
       body text around it. */
    #ai-extras-tabs .nav-link,
    .pr-tabs .nav-link {
        padding: 8px 5px 4px 5px;
        font-size: 14px;
        letter-spacing: .02em;
    }

    .ai-tab-icon {
        margin-right: 3px;
        opacity: .75;
    }
}

/* A finding somebody has dealt with ------------------------------------------

   Shown rather than removed. A list that quietly drops what has been done
   cannot answer "how much is left", and a writer who thumbed the wrong row
   has to be able to find what they did.

   The same three colours as the editor's sidebar, which is where these get
   set. The writer marks a finding in one place and reads it back in the
   other, and a tick that is green over there and grey over here is two
   different facts as far as anybody looking can tell.

   It was opacity .55 and a strikethrough, which is the treatment the sidebar
   started with and abandoned for the same reason: three quiet signals that
   all said the same thing, none of which announced itself, and a struck-out
   monospace quotation nobody could read -- on a page whose whole job is
   showing the writer what was found. */
.pr-find--fixed,
.pr-find--noted,
.pr-find--ignored {
    border-radius: 4px;
}

.pr-find--fixed {
    background: #eef7f0;
    box-shadow: inset 3px 0 0 #1f7a4d;
}

/* Amber: noted is not a finished thing. The writer took it on and has still
   to do it -- see classes/proofreadFinding.php. */
.pr-find--noted {
    background: #fdf7ea;
    box-shadow: inset 3px 0 0 #c08a2e;
}

.pr-find--ignored {
    background: #f5f5f5;
    box-shadow: inset 3px 0 0 #b8b8b8;
}

/* The quotation has a pale ground of its own, which over a tint reads as a
   white patch stuck on the row. Translucent instead, so it still lifts off
   the background but the state colour comes through it. */
.pr-find--fixed .pr-find-quote,
.pr-find--noted .pr-find-quote,
.pr-find--ignored .pr-find-quote {
    background: rgba(255, 255, 255, .55);
}

/* Quieter, not unreadable. The row is done, not gone. */
.pr-find--fixed .pr-find-note,
.pr-find--fixed .pr-find-fix,
.pr-find--noted .pr-find-note,
.pr-find--noted .pr-find-fix,
.pr-find--ignored .pr-find-note,
.pr-find--ignored .pr-find-fix {
    opacity: .7;
}

.pr-find-state {
    margin: 5px 0 0;
    font-size: .92rem;
    font-weight: 600;
}

.pr-find-state i { margin-right: 5px; }

.pr-find-state--fixed   { color: #1f7a4d; }
.pr-find-state--noted   { color: #96681c; }
.pr-find-state--ignored { color: var(--text-muted, #8a8a8a); }

/* Progress, beside the number that leads. */
.pr-total-done {
    display: block;
    font-size: .85rem;
    color: var(--text-muted, #8a8a8a);
}

/* ===========================================================================
   THE PUBLISHED COVERAGE PAGE  (pages/coverageshare.php)

   A coverage report at an address with no login behind it. The reader is a
   stranger who was sent a link -- a producer, a manager, a competition -- and
   very often on a phone.

   Everything below the hero is drawn by the same renderCoverage() the
   Coverage tab uses, and inherits .cv-* untouched. These rules are only the
   page around it: what a script is, above the opinion of it.
   =========================================================================== */

.cvs-page {
    max-width: 1040px;
    margin: 0 auto;
    padding: 28px 18px 60px;
}

/* What is being judged, before the judgement -------------------------------

   The poster earns its place here in a way it does not on a list. A reader
   who has been sent a link has no idea what they are looking at, and a score
   out of 100 attached to a title alone is a number about nothing. */
.cvs-hero {
    display: flex;
    align-items: flex-start;
    gap: 26px;
    margin-bottom: 26px;
}

.cvs-poster {
    flex: 0 0 190px;
}

.cvs-poster img {
    width: 100%;
    border-radius: 8px;
    border: 1px solid var(--border, #e0e0e0);
    display: block;
}

/* A real poster opens full screen, as on the summary page. */
.cvs-poster-zoom {
    cursor: zoom-in;
}

.cvs-herometa {
    flex: 1 1 auto;
    min-width: 0;
}

.cvs-title {
    margin: 0 0 6px;
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 2.1rem;
    line-height: 1.15;
    color: var(--color-text-body, #2c3e50);
}

.cvs-episode {
    margin: 0 0 6px;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--text-soft, #555);
}

.cvs-episode i { margin-right: 6px; opacity: .7; }

/* Type, length and author. Context for the score rather than a headline --
   a 45-page pilot and a 120-page feature are not judged by the same rules. */
.cvs-facts {
    margin: 0 0 12px;
    font-size: .95rem;
    color: var(--text-muted, #8a8a8a);
    text-transform: uppercase;
    letter-spacing: .04em;
}

.cvs-logline {
    margin: 0 0 10px;
    font-size: 1.12rem;
    line-height: 1.55;
    color: var(--color-text-body, #2c3e50);
}

.cvs-summary {
    margin: 0 0 12px;
    font-size: 1rem;
    line-height: 1.55;
    color: var(--text-soft, #555);
}

.cvs-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 12px;
}

/* Where the report comes from ---------------------------------------------

   Between the script and the judgement of it, because that is the order the
   reader needs: what is being judged, who is judging, then the judgement.

   The logo is here for the reason the whole page exists -- this is the one
   surface of the site a stranger sees, sent to them by somebody who liked
   what it produced. It is a rule and a mark, not a banner: whatever else
   this page is for, it is somebody's coverage first. */
.cvs-reporthead {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 18px;
    padding-bottom: 14px;
    border-bottom: 2px solid var(--border, #e0e0e0);
}

.cvs-reporthead img {
    flex: 0 0 auto;
    width: 116px;
    height: auto;
}

.cvs-reporthead h2 {
    margin: 0 0 3px;
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 1.5rem;
    color: var(--color-text-body, #2c3e50);
}

.cvs-reporthead p {
    margin: 0;
    font-size: .95rem;
    line-height: 1.45;
    color: var(--text-muted, #8a8a8a);
}

/* The report itself. No panel around it here -- see renderCoverage()'s
   'bare' option -- so this is just the space it sits in. */
.cvs-report {
    margin-bottom: 34px;
}

/* The verdict box on the public link, edged like the Library's score box.
 *
 * .mk-cov-box in css/marketplace.css is the model: a 3px border in
 * currentColor, which the .cv-verdict--{class} rules have already set to the
 * verdict's own text colour. So the edge is a darker shade of whatever the box
 * is filled with -- green on green for a Recommend, grey on grey for a Pass --
 * without this file naming any of the five a second time. Change a verdict
 * colour in one place and the border follows.
 *
 * SCOPED TO THIS PAGE, and deliberately. .cv-verdict is also the Coverage tab
 * on a script page, where the report sits inside a panel that already has a
 * border of its own and a second heavy edge a few pixels inside the first
 * reads as a mistake. Here the report IS the page: there is no panel around
 * it, nothing else drawing a line, and this is the first thing a stranger
 * opening the link sees. It is the one place the box has to hold the page on
 * its own. */
.cvs-report .cv-verdict {
    border: 3px solid currentColor;
}

/* The one thing asked of the reader --------------------------------------

   After the report, not before it. Somebody who has just read three thousand
   words about a screenplay is in a position to want one of their own; the
   same offer at the top is an advertisement in front of the thing they came
   for. */
.cvs-cta {
    padding: 26px;
    border: 1px solid var(--border, #e0e0e0);
    border-radius: 10px;
    background: #f7faf8;
    text-align: center;
}

.cvs-cta-lead {
    margin: 0 0 6px;
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--color-text-body, #2c3e50);
}

.cvs-cta-sub {
    margin: 0 0 18px;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--text-soft, #555);
}

.cvs-cta-btn {
    display: inline-block;
    padding: 10px 22px;
    border-radius: 6px;
    background: #36a857;
    color: #fff;
    font-size: 1rem;
    font-weight: 600;
    text-decoration: none;
    transition: background .15s ease;
}

.cvs-cta-btn:hover { background: #2b8c48; color: #fff; }

/* The blocks on a public SCRIPT link ---------------------------------------

   pages/scriptshare.php reuses everything above -- the hero, the chips, the
   CTA, the gone page -- and adds one thing the coverage page has no use for:
   a stack of .mk-ai-block sections holding the cast, the images, the coverage
   and the story breakdown. Those are the Script Library listing's own blocks,
   drawn by the Library's own renderers, so css/marketplace.css dresses them
   and there is nothing to restate here.

   All this does is give the stack the same breathing room the hero and the
   CTA have, so the page reads as three parts rather than one run-on. */
.cvs-blocks {
    margin: 22px 0 26px;
}

/* A picture, opened.

   js/dashboard.js owns openPosterLightbox() everywhere else and mounts it in
   a #poster-lightbox that lives in the dashboard's markup. Neither is on a
   public page, so pages/scriptshare.php defines a standalone one and this
   dresses it: full-bleed, dim, click or Escape anywhere to leave. */
.cvs-lightbox {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, .82);
    cursor: zoom-out;
}

.cvs-lightbox img {
    max-width: 100%;
    max-height: 100%;
    border-radius: 4px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, .5);
}

/* A link that no longer opens anything ------------------------------------

   One message for every way it can fail -- revoked, deleted, never real.
   The reader can act on none of them, and naming which it was would be
   telling a stranger something about somebody else's script. */
.cvs-gone {
    max-width: 520px;
    margin: 60px auto;
    padding: 34px 26px;
    border: 1px solid var(--border, #e0e0e0);
    border-radius: 10px;
    text-align: center;
}

.cvs-gone i {
    font-size: 2.4rem;
    color: var(--text-muted, #b0b0b0);
    margin-bottom: 14px;
}

.cvs-gone h1 {
    margin: 0 0 10px;
    font-size: 1.5rem;
    color: var(--color-text-body, #2c3e50);
}

.cvs-gone p {
    margin: 0 0 20px;
    line-height: 1.55;
    color: var(--text-soft, #555);
}

/* The phone, which is where a forwarded link is most often opened. */
@media (max-width: 700px) {

    .cvs-hero {
        flex-direction: column;
        align-items: center;
        text-align: center;
        gap: 18px;
    }

    .cvs-poster { flex: 0 0 auto; width: 150px; }

    .cvs-chips { justify-content: center; }

    .cvs-title { font-size: 1.6rem; }

    /* Stacked, and the logo smaller -- at 116px beside two lines of text it
       takes a third of a phone's width for no gain. */
    .cvs-reporthead {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
    }

    .cvs-reporthead img { width: 92px; }
}

/* Where the cast went ---------------------------------------------------------

   The Breakdown writes the major characters into the writer's own character
   records, so the Character section says so rather than listing them a second
   time. Tinted and iconed because it is a pointer to somewhere else on the
   page, not another finding to read. */
.ai-x-cast-note {
    margin: 10px 0 0;
    padding: 8px 11px;
    border-left: 3px solid var(--color-blue, #005e6a);
    border-radius: 0 4px 4px 0;
    background: #f2f7f8;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-soft, #555);
}

.ai-x-cast-note i {
    margin-right: 7px;
    color: var(--color-blue, #005e6a);
}

/* The breakdown's offer -------------------------------------------------------

   Two short lists rather than a paragraph, because the question a writer has
   in front of a tab called Breakdown next to a tab called Coverage is 'which
   one do I want and what do I get' -- and a list can be checked against what
   arrives, where a paragraph cannot. */
.ai-offer-lead {
    margin: 16px 0 6px;
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--color-blue, #005e6a);
}

.ai-offer-list {
    margin: 0;
    padding-left: 20px;
    line-height: 1.6;
}

.ai-offer-list li { margin-bottom: 5px; }

.ai-offer-foot {
    margin: 16px 0 18px;
    font-size: .95rem;
    color: var(--text-muted, #8a8a8a);
}

/* What the reading could not settle ------------------------------------------

   A box like the rest, because it is a section of the breakdown and not a
   footnote to it -- it is the honest half of the reading and often the most
   actionable. Amber rather than the neutral ground the others use: this one
   is asking the writer to go and decide something. */
.ai-x-confidence {
    margin-bottom: 12px;
    padding: 14px 16px;
    border: 1px solid #eadfc4;
    border-left: 4px solid #c08a2e;
    border-radius: 6px;
    background: #fdf9f0;
    font-size: 1.05rem;
    line-height: 1.55;
    color: var(--text-soft, #555);
}

.ai-x-confidence strong {
    display: block;
    margin-bottom: 6px;
    font-size: 1.2rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: #96681c;
}

/* The rebuild question on Re-analyse.

   Set apart from the price above it with a rule, because it is not a cost --
   it is what the run is allowed to do to work the writer has already done, and
   reading it as another line item would be the wrong kind of skim. */
.ai-rebuild-pick {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border, #dbdfea);
    text-align: left;
}

/* Nothing about the type here. The label and the note are styled with the
   choices above them -- see .ai-quote-pick label and .ai-quote-aside -- so the
   two cannot drift apart again. This rule is only the space around them. */
.ai-rebuild-pick .ai-quote-aside {
    margin-top: 4px;
}

/* The standalone note, set against the left edge rather than hung off a line
   item, with room to breathe above the total it explains. */
.ai-quote-aside.ai-quote-solo {
    padding-left: 0;
    margin: 0 0 10px;
    text-align: left;
}

/* ── The coverage popup ───────────────────────────────────────────────────

   The report from the file-pen icon on a script card, opened by
   openScriptCoverage() in js/dashboard.js into the site's own #modal360.

   Nothing here dresses the REPORT -- that is .cv-report and the two hundred
   lines above it, drawn by the same renderCoverage() the Coverage tab and the
   public share page use. This is only the box around it.

   Wider than the cast popup because a report is prose in seven scored
   categories, and at the dialog's default width the evidence quotes wrap to
   four words a line. Tall, with the report scrolling inside rather than the
   dialog running off the bottom of the screen: three thousand words is normal
   here. */
.sc-cov-dialog {
    width: 900px;
    max-width: 100%;
}

.sc-cov-dialog .dialogBoxContents {
    max-height: 74vh;
    overflow-y: auto;
}

/* The pitch, narrower than the coverage it borrows this dialog from.
 *
 * .pt-pitch is capped at 70ch -- a measure chosen so a paragraph of sales copy
 * reads without the eye losing its place -- so in the 900px box above it drew
 * a column of text with a third of the dialog empty beside it, which reads as
 * a layout that failed rather than as a deliberate measure.
 *
 * 42rem is that 70ch plus the dialog's own padding, near enough: the text now
 * reaches both edges and the box is the shape of what is in it. max-width
 * still wins on a phone, where 100% is narrower than this. */
.sc-ai-dialog--pitch {
    width: 42rem;
}

/* And the measure comes off inside, or the two caps fight: whichever is
   smaller wins, and a 70ch column inside a 42rem box would leave the gap this
   rule exists to close. The dialog IS the measure now. */
.sc-ai-dialog--pitch .pt-pitch {
    max-width: none;
}

/* ── The one-page synopsis ────────────────────────────────────────────────

   The Synopsis tab in AI Extras. It is a page of prose and it is drawn as
   one: a measure that keeps lines readable, space between paragraphs, and no
   box -- the tab is already the box, and a second frame around a page of text
   makes it look like a quotation from somewhere else.

   Everything here is drawn by renderSynopsisResult() in
   includes/synopsisrender.php. */

.ai-synopsis {
    padding-top: 2px;
}

/* One panel is one version now -- the full page and the short version are two
   panels, each with its own title, its own buttons and its own bin. What used
   to be here (.ai-synopsis-binrow, .ai-synopsis-part, .ai-synopsis-parthead)
   described the two-blocks-in-one-panel layout and went with it. */

/* The page itself.

   A measure, because this is the one thing here that is read straight through
   rather than scanned -- across the full width of the card a 600-word page
   runs to 130 characters a line, which is roughly twice what anybody reads
   comfortably. */
.ai-synopsis-text {
    max-width: 68ch;
    font-size: 0.98rem;
    line-height: 1.68;
}

.ai-synopsis-text p {
    margin: 0 0 0.95em;
}

.ai-synopsis-text p:last-child {
    margin-bottom: 0;
}

/* What the model could not do. A footnote on the page rather than a warning
   above it -- see the note in renderSynopsisResult(). */
.ai-synopsis-note {
    max-width: 68ch;
    margin: 14px 0 0;
    padding: 8px 11px;
    border-radius: 6px;
    background: var(--panel-body-bg, #fdfbf5);
    border: 1px solid var(--gold-light, #e3d6b4);
    font-size: 0.88rem;
    color: var(--text-soft, #6b6b6b);
}

.ai-synopsis-note i {
    margin-right: 6px;
}

/* At the top of the panel, above the text.
   Somebody who has decided by the second paragraph should not scroll five
   hundred words to act on it. */
.ai-synopsis-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin: 0 0 14px;
}

/* The bin to the far end, away from the buttons somebody means to press. It
   had a row of its own above these, which read as a heading made out of a
   delete button. */
.ai-synopsis-actions .syn-del-one {
    margin-left: auto;
}

/* The page that is currently in scripts.synopsis.

   Still a button -- it can be pressed again after the field has been edited by
   hand -- but it is reporting a state rather than offering an action, so it
   reads as a label with a tick and not as the thing to click. */
.ai-synopsis-use.is-applied {
    border-color: var(--primary, #2e7d5b);
    color: var(--primary, #2e7d5b);
    cursor: default;
}

/* Said once, under the button that makes it true. */
.ai-synopsis-where {
    max-width: 68ch;
    margin: 8px 0 0;
    font-size: 0.83rem;
    color: var(--text-soft, #6b6b6b);
}

/* The line that stands in for the result before there is one. Not
   .ai-tab-empty, which is the centred grey line a reader sees on a tab with
   nothing in it -- this is addressed to the author and it is an offer. */
/* The description on the Synopsis and Pitch tabs. The same size, leading and
   full width as the other tabs' descriptions -- the Proofreading tab's
   .cv-pitch and the Breakdown tab's offer (Ben, 2026-10-01). It was 0.8rem
   and capped at 68ch, which made these two the odd ones out. */
.ai-tab-lead {
    margin: 4px 0 8px;
    font-size: .93rem;
    line-height: 1.6;
    color: var(--text-soft, #6b6b6b);
}

/* ══ THE PITCH ══════════════════════════════════════════════════════════════
 *
 * The one thing the AI writes here to persuade rather than to report, and it
 * is set to be read that way: the hook given its own weight, the case in
 * ordinary prose under it, and the three short answers held apart from both.
 *
 * Quieter than coverage on purpose. A report earns its colour -- the verdict
 * bands mean something and the reader is looking for them. A pitch that
 * arrived striped and badged would be selling itself rather than the
 * screenplay, which is the failure the prompt spends most of its length
 * avoiding. Nothing in here is coloured but the hook's rule.
 */
.pt-pitch {
    max-width: 70ch;
}

/* The sentence the reader is meant to repeat afterwards. Larger than the
   prose, and the only thing in the block with a rule against it -- it does a
   different job from everything below it and should not have to be found. */
.pt-hook {
    margin: 0 0 16px;
    padding-left: 14px;
    border-left: 3px solid var(--gold);
    font-size: 1.15rem;
    line-height: 1.45;
    font-weight: 600;
    color: var(--text-dark);
}

/* Clear of the hook above it.
 *
 * The hook's own 16px is the gap between two blocks of prose, which is right
 * when the body is only text. It is not enough once the body can be focused:
 * .pt-edit pulls itself up 4px to make room for its padding, and the focus
 * ring is drawn outside the padding again -- so the ring was landing on the
 * last line of the hook. */
.pt-body {
    margin-top: 10px;
}

.pt-body p {
    margin: 0 0 14px;
    line-height: 1.6;
}

.pt-body p:last-child {
    margin-bottom: 0;
}

/* Why now, The role, Audience, Comparable titles.
 *
 * Under the prose and set in from it, because they are answers to questions
 * the pitch raises rather than part of its argument -- a producer reads the
 * case, then looks for these. Any of them may be missing: the prompt would
 * rather say nothing than manufacture a reason, and renderPitch() draws no
 * heading over an empty one. */
.pt-aside {
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}

.pt-aside p {
    margin: 0;
    line-height: 1.55;
    color: var(--text-soft);
}

.pt-aside-head {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0 0 5px;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.pt-aside-head i {
    font-size: .9rem;
    opacity: .75;
}

/* The comps read as a set of names rather than a sentence, so they are spaced
   as one and not left to look like prose that forgot its verbs. */
.pt-comps {
    font-style: italic;
}

/* ── EDITING A PITCH, AND THE TWO BUTTONS UNDER IT ────────────────────────
 *
 * The fields are contenteditable rather than inputs, so the panel stays a
 * document: a writer corrects a comp where it sits instead of putting the page
 * into an edit mode first. That means they have to LOOK editable without
 * looking like a form -- hence a hover and a focus state and nothing at rest.
 */
/* The cursor and the hover underline are NOT here. They are on
   .inline-field.is-editable in css/dashboard.css, which .pt-edit now shares --
   the note there says three pages offer this and should teach it once, and
   this is the fourth. A second pencil defined in this file would be a second
   thing to keep in step.

   Room for the focus ring, taken back with an equal negative margin so the
   text does not move when the field gains or loses it. A ring drawn hard
   against the words reads as an error state rather than as a field. */
.pt-edit {
    padding: 4px 7px;
    margin: -4px -7px;
    outline: none;
    transition: background .15s, box-shadow .15s;
}

/* The hook keeps its indent and its gold rule exactly where they were: only
   the vertical room and the right-hand room are added, so the border does not
   shift left when the padding arrives. */
.pt-hook.pt-edit {
    padding-left: 14px;
    margin-left: 0;
}

.pt-edit:focus {
    background: var(--bg-white, #fff);
    box-shadow: 0 0 0 2px var(--primary);
}

/* Empty and not focused. Without this an unanswered "Why now" is a heading
   over nothing, which is what the reader's copy avoids by skipping the block
   entirely -- the writer keeps it, so the writer needs to see it is empty. */
.pt-edit:empty::before {
    content: attr(data-placeholder);
    color: var(--text-muted);
    font-style: italic;
}

/* The pitch body while it is being edited. Paragraph breaks are newlines in
   the stored text, so the block has to keep them; as separate <p>s each would
   save on its own and a new blank line would have nowhere to go. */
.pt-body-edit {
    white-space: pre-wrap;
    line-height: 1.6;
    min-height: 6em;
    /* Said again because .pt-edit's margin shorthand above resets it to -4px,
       and stated as 6 rather than 10: the 4px of padding underneath puts the
       first line in the same place the read-only body starts, so the text does
       not jump when the panel goes from being read to being edited. */
    margin-top: 6px;
}

/* In flight, and just saved. Deliberately quiet: a save that took is not news,
   and the writer is still reading the sentence they changed. */
.pt-edit.is-saving {
    opacity: .6;
}

.pt-edit.is-saved {
    background: var(--success-tint);
}

.pt-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}

.pt-copy,
.pt-del {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 13px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-white);
    color: var(--text-soft);
    font: inherit;
    font-size: .85rem;
    font-weight: 600;
    cursor: pointer;
    transition: border-color .15s, color .15s, background .15s;
}

.pt-copy:hover {
    border-color: var(--primary);
    color: var(--primary);
}

/* Delete is pushed to the far end and stays grey until it is reached for.
   A red button sitting beside Copy invites the wrong one. */
.pt-del {
    margin-left: auto;
}

.pt-del:hover {
    border-color: var(--danger);
    color: var(--danger);
    background: var(--danger-tint);
}

/* ── A PITCH SHOWN AS AN EXAMPLE ──────────────────────────────────────────
 *
 * The FAQ topic "Can I create a pitch for my screenplay?" reproduces a real
 * pitch, and it reuses .pt-pitch and everything under it rather than being
 * marked up as a quotation -- so what a writer reads in the FAQ is the same
 * object they will see in the tab, down to the gold rule on the hook. A
 * blockquote would have described the feature; this shows it.
 *
 * That works because the FAQ renders on the dashboard, which already loads
 * this stylesheet. If the FAQ ever moves to a page of its own, the .pt- rules
 * have to go with it.
 *
 * This wrapper is the only thing added: a card around the specimen so it reads
 * as a thing being exhibited rather than as the page's own voice continuing in
 * a different font. */
.pt-faq-sample {
    margin: 18px 0 22px;
    padding: 20px 22px;
    background: var(--panel-body-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
}

/* The answer around it sets 16px and a 1.7 line-height for long explanation.
   Inside the specimen the pitch takes its own measure back, or it is a pitch
   quoted in somebody else's typography. */
.pt-faq-sample .pt-pitch {
    font-size: 15px;
    line-height: 1.6;
    color: var(--text-dark);
    max-width: none;
}

.pt-faq-sample .pt-body p {
    line-height: 1.6;
}

/* The FAQ gives every <p> a bottom margin for prose; the asides here space
   themselves with their own rule above the heading. */
.pt-faq-sample .pt-aside p {
    margin: 0;
}

/* An analyst's report in the Coverage stack -- renderProfessionalCoverage()
   in includes/coverageprofessional.php. It borrows the AI report's pieces
   (.cv-verdict, .cv-cats, .cv-overview-box); these are its own. */
.cv-pro-title {
    margin: 4px 0 10px;
    font-family: var(--font-title, 'Playfair Display', serif);
    font-size: 1.25rem;
    color: var(--text-main, #2f2f2f);
}

.cv-pro-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 18px;
    margin: 0 0 12px;
    font-size: .92rem;
    color: var(--text-soft, #6b6b6b);
}

.cv-pro-section {
    margin: 16px 0 0;
}

/* Each section of the writing in a box of its own on screen -- the AI
   report's category box, .cv-cat (Ben, 2026-09-30). A section with no score
   has the Overview box's slate edge rather than .cv-cat--none's grey. */
.cv-pro-boxes {
    margin-top: 18px;
}

.cv-pro-box.cv-cat--none {
    border-left-color: #5b7c93;
}

.cv-pro-box .cv-cat-head {
    margin-bottom: 8px;
}

.cv-pro-box .cv-pro-rich > :last-child,
.cv-pro-box .cv-pro-text {
    margin-bottom: 0;
}

/* In print, no boxes: the section's name as a heading and the text under it
   -- includes/coverageprint.php. */
.cv-pro-plain {
    margin: 18px 0 0;
}

.cv-pro-plain-head {
    margin: 0 0 6px;
    padding-bottom: 3px;
    border-bottom: 1px solid #d9dfe4;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--text-soft, #555);
}

.cv-pro-rich {
    font-size: .95rem;
    line-height: 1.6;
    color: var(--text-main, #2f2f2f);
}

.cv-pro-rich p {
    margin: 0 0 10px;
}

.cv-pro-rich ul,
.cv-pro-rich ol {
    margin: 0 0 10px;
    padding-left: 1.3rem;
    list-style: disc;
}

.cv-pro-rich ol {
    list-style: decimal;
}

/* The score beside a category's comment in an analyst's First Act Review. */
.cv-pro-score {
    margin-left: 6px;
    font-weight: 600;
    color: var(--text-muted, #8a8a8a);
}
