/* css/character.css
 *
 * The Characters sidebar panel and the add/edit dialog.
 *
 * Namespaced .sc- throughout, so this is safe to load anywhere -- the same
 * arrangement css/storyboard.css uses with .sb-.
 *
 * The palette is the board's: the gold accent for anything the writer has
 * claimed, neutrals for everything the script merely reports. A character that
 * has been written up is the writer's own work, so the tracked list wears the
 * accent and the untracked names underneath stay grey.
 */

/* ---------------------------------------------------------------- the panel */

.sc-panel {
    padding: 0 4px 12px;
    /* A flex item in #sidebarcontent, which is a fixed-height column. min-height
       is the line that lets it shrink far enough to scroll rather than run off
       the bottom -- the same pair .scene-list needs. */
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

/* The editor styles every paragraph in the sidebar as prose -- floated left at
   full width, with one fixed margin -- in `#sidebarcontent p`
   (editor/css/pr-editor.css). That suits the panels that are prose. It does not
   suit this one, in two ways:

   The float: anything after a heading that establishes its own formatting
   context -- a flex row, a scroller -- is placed beside those floats rather than
   below them, and a full-width float leaves nowhere to go but off the right
   edge.

   The margin: at (1,0,1) it outranks any class, so every margin this file sets
   on a paragraph was quietly discarded and the headings sat on what came before
   them.

   Scoped by #sidebarcontent so it only answers that rule where that rule
   applies, and so it outranks it. The paragraph rules below each carry a second
   selector for the same reason -- the values stay written once, and apply both
   in the sidebar and wherever this panel is used next. */
#sidebarcontent .sc-panel p {
    float: none;
    width: auto;
}

.sc-panel .sc-empty,
#sidebarcontent .sc-panel .sc-empty {
    color: #6b6b7a;
    font-size: 13px;
    line-height: 1.5;
    margin: 10px 2px;
}

/* The role a group of characters share.
 *
 * Quieter than .sc-heading below, which separates the written-up characters from
 * the names the script merely knows -- that is a division between two kinds of
 * thing, while this is a division within one kind. Same family, less weight.
 *
 * Two selectors for the same reason every paragraph in this panel needs them:
 * #sidebarcontent p floats and re-margins anything in the editor's sidebar, and
 * an id beats a class. */
.sc-panel .sc-role,
#sidebarcontent .sc-panel .sc-role {
    margin: 12px 2px 3px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: #8d8781;
}

/* The first group sits directly under the button above it and needs no gap of
   its own; only the ones after it are separating themselves from a list. */
.sc-panel .sc-role:first-child,
#sidebarcontent .sc-panel .sc-role:first-child {
    margin-top: 2px;
}

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

.sc-item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 6px 6px;
    border-radius: 6px;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
}

.sc-item:hover {
    background: #f3f2f2;
}

/* Square rather than round: these are reference pictures a writer has pinned up,
   not profile avatars, and a square keeps more of what was in the frame. */
.sc-thumb {
    flex: 0 0 34px;
    width: 34px;
    height: 34px;
    border-radius: 5px;
    background: #e2dedb;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    color: #8d8781;
    font-size: 14px;
}

.sc-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* min-width:0 so a long name ellipses instead of pushing the row wider than the
   sidebar -- a flex item will not shrink below its content without it. */
.sc-item-text {
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

/* Upper case, as a cue is written. The name is stored however it was typed --
   the record keeps what the writer wrote -- and shown the way the script says
   it, which is also how it appears on a scene card. */
.sc-item-name {
    font-size: 13.5px;
    font-weight: 600;
    color: #201e1d;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sc-item-sub {
    font-size: 11.5px;
    color: #6b6b7a;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The space above is the point of this element: it is what separates the names
   the script knows from the characters already written up. */
/* 14px, so it stays above the 13.5px note it introduces. At 12 against 13.5 the
   heading was SMALLER than the sentence under it, and uppercase and bold were
   the only things saying it was a heading at all. */
.sc-panel .sc-heading,
#sidebarcontent .sc-panel .sc-heading {
    margin: 16px 2px 2px;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-dark);
}

/* 13.5px. These are not captions -- they are the instructions for a panel that
   is empty until somebody follows them, and at 11.5 they read as small print
   under the thing they are meant to explain. */
.sc-panel .sc-note,
#sidebarcontent .sc-panel .sc-note {
    margin: 0 2px 8px;
    font-size: 13.5px;
    color: #6b6b7a;
}

/* Names the script knows and nobody has written up. Dashed like the empty
   dropzone in the dialog: both are somewhere with nothing in it yet. */
.sc-untracked-select {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    /* Stated, not inherited. editor/css/pr-editor.css resets margin to 0 on
       every input, select, textarea and button, so a select in this panel has
       nothing of its own to fall back on. The 2px sides line the box up with the
       heading and the note above it, which carry the same. */
    margin: 0 2px 10px;
    padding: 6px 8px;
    border: 1px solid #bb9378;
    border-radius: 6px;
    background: transparent;
    color: #4a4644;
    font-size: 12.5px;
    font-family: inherit;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
}

.sc-untracked-select:hover,
.sc-untracked-select:focus {
    border-style: solid;
    border-color: var(--gold, #c9a84c);
    background: #f7f0dc;
    outline: none;
}

/* Not the whole page, where there is a whole page.

   100% is right in the sidebar, which is 260px of column. On the script
   summary page the same rule stretched the dropdown across the widget, where a
   control that wide reads as a field to fill in rather than as a way in --
   and it dwarfed the cards it feeds.

   Capped rather than fixed, so it still shrinks on a narrow window. 340px is
   the width a character card stops at, so the two line up. */
.sc-panel--wide .sc-untracked-select {
    max-width: 340px;
}

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

.sc-dialog {
    width: min(620px, 92vw);
}

.sc-top {
    display: flex;
    gap: 16px;
    align-items: flex-start;
}

.sc-fields {
    flex: 1 1 auto;
    min-width: 0;
}

/* Two per line where the values are short. Collapses to one on a narrow modal,
   which is where the dialog ends up on a phone. */
.sc-row {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
}

.sc-row>.form-group {
    flex: 1 1 150px;
    min-width: 0;
}

/* Three to a line rather than two and a stray.

   At a 150px basis a third field cannot fit beside the other two, so it wraps
   -- and alone on its line, flex-grow stretches it the full width of the form,
   which is how a Race dropdown came to be as wide as the Biography box. A
   smaller basis for the rows that hold three lets them sit together, and the
   flex-wrap above still drops them onto their own lines when the dialog is
   narrow. */
.sc-row--three>.form-group {
    flex: 1 1 105px;
}

/* Not this dialog's to change. The same grey, the same cursor and the same
   reasoning as .sb-slug-row.is-locked on a card the screenplay owns. */
.sc-dialog .dialog-field[readonly] {
    background: #f3f2f2;
    color: #6b6664;
    cursor: not-allowed;
}

.sc-field-note {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin: 4px 0 0;
    font-size: 11.5px;
    line-height: 1.35;
    color: #8d8781;
}

.sc-field-note i {
    font-size: 10px;
}

/* 156 rather than 140.

   The portrait and everything under it share one width, and what is under it
   now includes the sketch button -- "Sketch Character" does not fit on one line
   at 140. Widened here rather than letting the button break out of the column,
   so the picture, Remove image and the button all still line up. The fields
   beside it lose the 16px, which they have to spare. */
/* 128, down from 156.
 *
 * The frame went from a square to 2:3 so the sketches stopped being cropped,
 * and at the old width that made it 234px tall -- which pushed the Sketches
 * button well below the fields beside it and left the dialog mostly air.
 * Narrowing the column buys the height back: 128 wide is 192 tall, 42px less,
 * and the picture is the same shape either way.
 *
 * Not narrower than this. .sc-sketch-btn is width:100% of this column and has
 * to hold "Sketch Character" on one line; it ellipsises rather than wrapping,
 * so the failure is quiet and ugly rather than obvious. 128 leaves about 110px
 * of text room, which that label fits. */
/* 3px, so the Sketches button sits right under the picture.
 *
 * This gap is the ONLY space between them now -- .sc-sketch-btn had 8px of
 * top margin as well, which stacked on top of it. Tight is right here: the
 * button is about the picture above it, and air between them made them look
 * like two unrelated controls that happened to share a column. */
/* min-width:0, or the basis above is only a suggestion.
 *
 * A flex item's automatic minimum size is its content's min-content width, and
 * the sketch button under the picture sets its text nowrap -- so the column
 * grew to whatever the label measured and took the frame with it. A character
 * with sketches showed a 136px picture and one without showed a 169px picture,
 * in the same dialog, because "Sketch Character" is a longer string than
 * "Sketches (9)". 0 makes 128 mean 128, and the button ellipsises inside it as
 * it always said it would. See .sc-dialog .sc-sketch-btn in css/ai-images.css,
 * which is where the label was also quietly rendering at 16px. */
.sc-portrait {
    flex: 0 0 128px;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

/* THE SHAPE OF THE PICTURES THAT GO IN IT, not a square.
 *
 * It was 156x156. Every sketch the site draws comes back 2:3 portrait -- 38 of
 * the 40 on this machine measure 0.671, and the two that do not are uploads --
 * so with object-fit:cover below, a square frame threw away the top and bottom
 * of every one of them. Which on a picture of a person is their head and their
 * feet.
 *
 * aspect-ratio rather than a second fixed number, so the frame follows the
 * column width above and the two cannot drift apart. 128 wide makes it 192
 * tall; changing .sc-portrait is the only edit either of them needs.
 *
 * cover is kept deliberately. contain would letterbox an upload that is not
 * 2:3, and a frame with bars down the sides looks broken in a way a slight
 * crop does not -- now that the frame matches what the AI produces, the
 * ordinary case is not cropped at all.
 */
.sc-dropzone {
    position: relative;
    width: 100%;
    aspect-ratio: 2 / 3;
    border: 2px dashed #cfc9c5;
    border-radius: 8px;
    background: #faf8f3;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    overflow: hidden;
    transition: border-color .2s, background .2s;
}

.sc-dropzone:hover,
.sc-dropzone.is-over {
    border-color: var(--gold, #c9a84c);
    background: #f7f0dc;
}

/* Solid once there is something in it: the dashes say "put something here", and
   they have stopped being true.

   The cursor changes with them. A pointer on a filled frame promises the file
   dialog it used to open; zoom-in promises what it does now, which is to show
   the picture full size. */
.sc-dropzone.has-image {
    border-style: solid;
    border-color: #e4e0d6;
    background: #fff;
    cursor: zoom-in;
}

.sc-dropzone img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.sc-dropzone-prompt {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    padding: 8px;
    text-align: center;
    color: #8d8781;
    font-size: 11.5px;
    line-height: 1.35;
    pointer-events: none;
}

.sc-dropzone-prompt i {
    font-size: 26px;
    color: #cfc9c5;
}

/* The X on the picture.

   Hidden by default and shown by .has-image on the dropzone, rather than by an
   inline style: the class is already maintained everywhere the picture changes
   -- the upload preview, the remove, and the AI sketch picker -- so there is
   one thing to keep right instead of two that can disagree.

   Dark on a translucent ground rather than a red link, because it sits on top
   of somebody's portrait and has to be legible over hair, sky or a white
   collar without shouting at any of them. */
.sc-image-remove,
.sc-image-replace,
.sc-image-download {
    display: none;
    position: absolute;
    top: 6px;
    width: 24px;
    height: 24px;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(20, 16, 12, .55);
    color: #fff;
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    transition: background .15s;
}

.sc-image-remove {
    right: 6px;
}

/* Beside the X, and the same size: these are a pair, and one of them being
   quieter than the other would be a claim about which is more likely. */
.sc-image-replace {
    right: 34px;
    font-size: 12px;
}

/* Third along. Text-decoration because it is an anchor and the dialog
   underlines those; nothing about this one should look like a link. */
.sc-image-download {
    right: 62px;
    font-size: 12px;
    text-decoration: none;
}

.sc-dropzone.has-image .sc-image-remove,
.sc-dropzone.has-image .sc-image-replace,
.sc-dropzone.has-image .sc-image-download {
    display: flex;
}

.sc-image-remove:hover {
    background: #b91c1c;
}

.sc-image-replace:hover,
.sc-image-download:hover {
    background: var(--primary, #6576ff);
    color: #fff;
}

/* ---- profession: one value, offered like a tag ---- */

/* The border, the corners and the padding come from .dialog-field in
   css/modal.css, which this element carries -- so it is outlined and sized like
   the inputs beside it, and stays that way if that rule changes. What is left
   here is the only part that is actually its own: a row that a chip and a caret
   share. */
.sc-prof-field {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    align-items: center;
    cursor: text;
}

/* With a chip in place there is nothing left to type -- one profession, so the
   entry goes rather than sitting there inviting a second. */
.sc-prof-field.full #sc-prof-entry {
    display: none;
}

/* Invisible: the wrapper is the box, and this is only the caret inside it. Its
   own padding would make the field taller than the inputs it sits beside, which
   is what the wrapper's .dialog-field padding is already for. */
#sc-prof-entry {
    flex: 1 1 90px;
    min-width: 70px;
    border: 0;
    outline: none;
    padding: 0;
    font: inherit;
    background: transparent;
}

/* Sized to stay just inside the height of the caret beside it, so a field with a
   chip in it is no taller than the empty one -- and no taller than the select it
   sits next to in the same row. */
.sc-prof-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #f7f0dc;
    border: 1px solid var(--gold, #c9a84c);
    color: #8a6f21;
    border-radius: 13px;
    padding: 0 6px 0 10px;
    font-size: .82rem;
    line-height: 1.55;
}

.sc-prof-chip button {
    border: 0;
    background: none;
    padding: 0;
    cursor: pointer;
    color: inherit;
    opacity: .6;
    font-size: .8rem;
    line-height: 1;
    display: flex;
    align-items: center;
}

.sc-prof-chip button:hover {
    opacity: 1;
    color: #b91c1c;
}

/* position:relative rather than absolute: the modal scrolls, and an absolutely
   positioned list detaches from the field the moment it does. */
/* What the list is positioned against. Only this field's group, so nothing else
   in the dialog gains a containing block it did not ask for. */
.sc-prof-group {
    position: relative;
}

.sc-prof-dropdown {
    display: none;
    /* Out of the flow, hanging from the bottom of the field.
     *
     * It was position:relative, on the reasoning that the dialog scrolls and an
     * absolutely positioned list would come adrift from its field. That was
     * wrong: absolute is measured against .sc-prof-group, which scrolls with
     * everything else, so the list stays where it belongs -- only `fixed` would
     * have detached. What relative actually did was leave the list in the flow,
     * so opening it grew the dialog and pushed Physical Appearance and Biography
     * down the screen.
     *
     * Out of flow it overlays them instead. The dialog's own box has
     * overflow:auto and a max-height, so a long list extends what can be
     * scrolled to rather than what the dialog measures. */
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    /* Above the fields it covers. Nothing else in the dialog sets a z-index, so
       this only has to beat the default. */
    z-index: 20;
    /* Hangs off the bottom of the field, so it wears the field's border and the
       field's corners -- the same token, and the same radius, as .dialog-field. */
    border: 1px solid var(--border);
    border-top: 0;
    border-radius: 0 0 4px 4px;
    background: #fff;
    max-height: 215px;
    overflow-y: auto;
    box-shadow: 0 3px 8px rgba(0, 0, 0, .07);
}

.sc-prof-dropdown.show {
    display: block;
}

.sc-prof-option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 11px;
    cursor: pointer;
    font-size: .88rem;
}

.sc-prof-option.active {
    background: #f4f6f9;
}

.sc-prof-option>i {
    color: #9aa5b1;
    font-size: .78rem;
}

.sc-prof-count {
    margin-left: auto;
    color: #9aa5b1;
    font-size: .78rem;
}

.sc-prof-create {
    border-top: 1px solid #eef0f3;
    color: #166534;
}

@media (max-width: 560px) {

    /* The portrait goes above the fields rather than beside them: at this width
       a 156px column leaves the name field too narrow to read what is in it. */
    .sc-top {
        flex-direction: column;
    }

    /* Centred above them, and still 128 wide. flex-basis:auto alone let the
       stacked frame take its width from its contents -- 172px against the
       128px the same picture has one pixel of window wider, which is the
       inconsistency the min-width:0 above exists to end. The width is stated
       here because the basis no longer applies across the column. */
    .sc-portrait {
        flex-basis: auto;
        width: 128px;
        align-self: center;
    }
}

/* ------------------------------------------------ the panel on an idea page

   The same markup as the sidebar, laid out across a page instead of down a
   260px column. One render path and one difference in the stylesheet, so a
   character that gains a field gains it in both places at once.

   The cards wrap rather than sit in fixed columns, because the number of them
   is what varies: a story with one protagonist and six supporting characters
   should not leave five empty slots in a grid, and a narrow window should not
   scroll sideways to reach the seventh. */

.sc-list--wide {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

/* Grow to share whatever the row has left, but never past a width where the
   line of prose underneath stops being readable, and never below one where the
   name has to ellipsis. Between those two the number per row is the window's
   business. */
.sc-list--wide .sc-item {
    flex: 1 1 240px;
    max-width: 340px;
    align-items: flex-start;
    padding: 10px;
    border: 1px solid var(--sb-line, #c9c5c3);
    border-radius: 6px;
    background: #fff;
}

/* The card and .idea-board answer a hover the same way, because they answer a
   click the same way: both open the thing they name. A tint as well as the gold
   edge -- a border alone is a small change to notice on a card this size, and it
   reads as decoration rather than as "this one".

   Its own rule rather than leaning on .sc-item:hover above. That one sets a
   background, but so does the card, with the same weight and further down the
   file, so the card's white won every time and the wide list has never shown a
   hover at all.

   --gold-tint is the gold lightened most of the way to white. It lives in
   global.css because the idea tiles and the dashboard tables wear it too, and
   a hover meaning the same thing in three places should not be three hex
   codes that happen to agree today.

   Not --sb-accent-tint, which is spoken for: that is what a selected or
   just-saved card wears on a board, and hovering is not selecting. */
@media (hover: hover) {

    .sc-list--wide .sc-item:hover {
        border-color: var(--gold, #c9a84c);
        background: var(--gold-tint, #faf7ef);
        box-shadow: 0 1px 0 rgba(32, 30, 29, .18);
    }
}

/* A face worth looking at rather than a marker beside a name.

   TALLER THAN IT IS WIDE, AND FOR A REASON

   2:3, which is the shape the sketches are generated in -- see
   aiImageSpec('image.character'). A square crops a portrait to its middle:
   .sc-thumb img is object-fit: cover, so 56x56 took a band across the face and
   threw away the top of the head and the shoulders, which on a charcoal study
   is most of what there was to look at.

   84 rather than something smaller because the card is already about that tall:
   a name, a line of facts and two clamped lines of prose inside 10px of
   padding. The picture now runs the height of the text beside it instead of
   floating at the top of a card with space under it.

   An uploaded photograph is cropped to 2:3 by the same cover rule, which is the
   right way round: the shape is the site's, and every card matches whether the
   picture was drawn or taken. */
.sc-list--wide .sc-thumb {
    flex: 0 0 56px;
    width: 56px;
    height: 84px;
    border-radius: 6px;
    font-size: 20px;
}

.sc-list--wide .sc-item-text {
    gap: 2px;
    padding-top: 1px;
}

.sc-list--wide .sc-item-name {
    font-size: 15px;
}

.sc-list--wide .sc-item-sub {
    font-size: 13.5px;
}

/* Two lines of what they look like, and the card stays the height it was.
   Clamped here rather than cut in the JS so the whole sentence is still in the
   page -- it is the dialog's to show in full, not this list's to throw away. */
.sc-list--wide .sc-item-blurb {
    margin-top: 3px;
    font-size: 13px;
    line-height: 1.3;
    color: #6b6b7a;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

/* Making one up, where there is no script to have named them. */
.sc-new-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 10px;
    padding: 6px 12px;
    border: 1px solid var(--sb-line, #c9c5c3);
    border-radius: 5px;
    background: #fff;
    color: #201e1d;
    font-family: var(--font-sans);
    font-size: 13px;
    cursor: pointer;
}

.sc-new-btn:hover {
    border-color: var(--sb-accent, #c9a84c);
    background: var(--sb-accent-tint, #f7f0dc);
}

/* On a page the panel is a section of it, not a column that scrolls on its own.
   The sidebar rule above makes it a scrolling flex item, which inside a page
   section would give the section its own scrollbar. */
.idea-section .sc-panel {
    padding: 0;
    flex: none;
    overflow: visible;
}

/* ------------------------------------------------ a character, read only

   What somebody invited to look over an idea gets when they click a name.

   Not the form with its controls disabled. A greyed-out field says "you may
   not touch this" about each line separately instead of simply showing the
   person, and it leaves a submit button on a dialog that has nothing to
   submit. This is a different thing, so it is drawn as one -- see the
   !$canEdit branch in popup/storyCharacter.php.

   It borrows .sc-top and .sc-portrait from the form above, because a face
   beside a handful of facts is the same arrangement whether or not the facts
   can be typed into. */

/* The column says 128 and means it now (see .sc-portrait above, which stopped
   letting its contents widen it), and the picture here is 156 -- so this view
   has to name its own width or the face hangs 28px over the facts beside it.
   156 rather than 128 because nothing about the reader's view changed: they
   were getting a slightly larger face than the writer's form gives, and that
   is the one thing this fix was not about. */
.sc-dialog--view .sc-portrait {
    flex: 0 0 156px;
}

.sc-dialog--view .sc-view-portrait {
    width: 156px;
    border-radius: 6px;
    display: block;
}

/* The short facts. A definition list rather than a two-column grid of divs:
   these genuinely are terms and their values, and a reader with a screen
   reader gets that for free. */
.sc-facts {
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 14px;
    margin: 0;
    align-content: start;
}

.sc-facts dt {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--sb-muted, #6b6664);
    /* Baselines, so a label sits on the same line as the value beside it
       rather than a pixel above it. */
    align-self: baseline;
}

.sc-facts dd {
    margin: 0;
    font-size: 15px;
    color: var(--sb-ink, #201e1d);
    align-self: baseline;
}

/* The prose below, one block per piece of writing that has any. */
.sc-view-block {
    margin-top: 16px;
}

.sc-view-head {
    margin: 0 0 4px;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--gold, #c9a84c);
}

/* 1.45 rather than the dialog's own leading: this is the only place in a
   character dialog where a paragraph is read rather than scanned. */
.sc-view-text {
    margin: 0;
    font-size: 15px;
    line-height: 1.45;
    color: var(--sb-ink, #201e1d);
}

/* A face you can look at properly ---------------------------------------------

   Only the ones that ARE pictures. The blank placeholder opens the character
   dialog like the rest of the row, so it must not advertise a zoom it does
   not do. Same cursor the script poster uses for the same promise. */
.sc-thumb-zoom {
    cursor: zoom-in;
    transition: filter .15s ease;
}

.sc-thumb-zoom:hover {
    filter: brightness(1.08);
}

/* THE X ON A CHARACTER ROW

   Off the list without opening the record first -- the Story Breakdown
   promotes everybody it judges major, and some of them are there to be
   dismissed.

   Hidden until the row is hovered, on a pointer device. It is a destructive
   control on every row of a list somebody is reading, and eight little crosses
   down the side turn a cast list into a form. On touch there is no hover to
   wait for, so it is simply always there.

   margin-left:auto rather than absolute positioning: .sc-item is a flex row,
   so this pins the button to the right edge and lets the text between take
   whatever is left. */
.sc-item .sc-item-x {
    flex: 0 0 auto;
    margin-left: auto;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: 5px;
    background: transparent;
    color: #a09a95;
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition: opacity .15s ease, background .15s ease, color .15s ease;
}

@media (hover: none) {
    .sc-item .sc-item-x {
        opacity: 1;
    }
}

.sc-item:hover .sc-item-x,
.sc-item .sc-item-x:focus-visible {
    opacity: 1;
}

/* Red only once it is under the pointer. Red on every row would read as eight
   errors rather than as eight ways to say no. */
.sc-item .sc-item-x:hover {
    background: #fdeceb;
    color: var(--danger, #e85347);
    opacity: 1;
}

/* On the wide cards the row is top-aligned and taller, so the button sits with
   the name rather than floating against the middle of a three-line card. */
.sc-list--wide .sc-item .sc-item-x {
    align-self: flex-start;
}

/* ── A card with nothing behind it ────────────────────────────────────────

   The cast popup, which openScriptCast() in js/character.js opens from the
   people icon on a script card. Every other panel on the site lists characters
   you can click into; this one is a glance at who is in a screenplay while
   somebody is scanning a shelf of them, and there is nothing to open.

   So the card stops pretending. No hand cursor and no hover tint, because both
   of those are a promise -- a row that lights up under the pointer and then
   does nothing when pressed is worse than one that never invited the press.

   The FACE keeps its own cursor: storyCharacterZoom() still works there, and
   .sc-thumb-zoom sets zoom-in on top of this. */
.sc-item--static {
    cursor: default;
}

.sc-item--static:hover {
    background: transparent;
}

/* The dialog around it.

   Wide, because the wide panel lays its cards out two and three across and the
   dialog's default width would stack them in a column. 760px is about four
   cards on a laptop and one on a phone, where the cap gives way to the
   viewport.

   The list scrolls rather than the dialog growing past the bottom of the
   screen: a script with fourteen promoted characters is not rare, and a popup
   you have to scroll the page behind to escape is a trap.

   860 because that is what two cards need. .sc-card has a 400px flex basis, so
   a row holds two of them only where there is 2 x 400 + 12 of gap = 812 of
   content, and the dialog's own padding is 24 on top. At the 790 this was, the
   popup would have dropped to one card per row the moment the basis went up.
   That number and this one move together. */
.sc-cast-dialog {
    width: 860px;
    max-width: 100%;
}

.sc-cast-dialog .dialogBoxContents {
    max-height: 70vh;
    overflow-y: auto;
}

/* ── Tabs and large cards ─────────────────────────────────────────────────

   The other shape the panel comes in -- see storyCharacterCardsHtml() in
   js/character.js. Today only the cast popup asks for it; the class names are
   deliberately not popup-specific, so the script summary page can take the
   same layout later without any of this moving. */

.sc-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 0 0 14px;
    border-bottom: 1px solid var(--border, #e6e3e0);
}

/* Sitting ON the border rather than above it, so the active tab joins the
   panel below and the inactive ones stay outside it. -1px is the border the
   row draws; without it the active tab has a line under it and reads as
   another inactive one. */
.sc-tab {
    position: relative;
    bottom: -1px;
    padding: 7px 13px;
    border: 1px solid transparent;
    border-bottom: none;
    border-radius: 6px 6px 0 0;
    background: none;
    color: var(--text-muted, #8a8a8a);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: color .15s ease, background .15s ease;
}

.sc-tab:hover {
    color: var(--text-soft, #555);
    background: #f3f2f2;
}

.sc-tab.is-active {
    border-color: var(--border, #e6e3e0);
    background: #fff;
    color: var(--color-text-body, #2c3e50);
}

/* The count, which is the reason the tabs earn their room: a cast with one
   protagonist and nine supporting players says so before anything is clicked. */
.sc-tab-count {
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 9px;
    background: #eceae8;
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted, #8a8a8a);
}

.sc-tab.is-active .sc-tab-count {
    background: var(--primary-dim, #e4f1f4);
    color: var(--primary, #06798e);
}

/* Two across, which is what "half the width" means once the gap is taken out
   of it.

   FLEX RATHER THAN GRID, AND THE REASON IS THE CAP

   This was an auto-fit grid of minmax(275px, 1fr) tracks, which is the usual
   answer and was the wrong one here. Capping the card at 600px inside a 1fr
   track does not move the track: the card shrinks to 600 and sits at the start
   of it, so two characters on a wide page ended up with a canyon between them.

   Capping the TRACK instead -- minmax(275px, 600px) -- breaks worse. CSS counts
   auto-fit repetitions using the max of minmax whenever it is definite, so the
   browser would lay out 600px columns to decide how many fit: one column at
   900px, one at 1100px. Fewer columns than today, on exactly the screens that
   have room for more.

   Flex has neither problem. Items are packed from the start with nothing
   between them but the gap, they grow into the space up to their max-width, and
   what is left over collects at the end of the row where it belongs.

   275px basis: the floor has to leave a readable column of text BESIDE a 111px
   portrait. At 260 a card was 111 for the picture, 12 for the gap and 24 for
   the padding, leaving 113px -- about two words a line. Below the basis the row
   wraps, which on a phone is one card wide and correct. */
.sc-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.sc-card {
    display: flex;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--border, #e6e3e0);
    border-radius: 8px;
    background: #fff;

    /* Grows into the row, and stops at 600.
     *
     * The basis is the narrowest a card may be before the row wraps; the grow
     * is what shares out whatever is left; the cap is what stops one character
     * on a full-window page from drawing a card a metre wide with a 111px
     * portrait stranded at one end of it.
     *
     * A cap rather than a percentage: it needs no breakpoint. Below about 600px
     * of row the card is already narrower than this and the rule does nothing,
     * so a phone gets a card the width of its screen without being told to. It
     * bites only where there is spare room, which is the only place the problem
     * exists.
     *
     * THE BASIS IS 400 BECAUSE OF WHAT A LAPTOP DID WITH 275
     *
     * The script summary page is full-window, so at 275 a 1400px laptop fitted
     * FOUR cards across at 341px each. Take away the 111px portrait, the gap
     * and the padding and that leaves under 200px of text -- three or four
     * words a line, every field a ragged little column. The type was not
     * smaller; there was simply nowhere for it to go.
     *
     * 400 puts three across on that laptop at 459px each, two on anything
     * narrower, and does not reach four until about 1800px. Every step up is
     * the same trade in reverse: fewer characters visible at once, each of them
     * actually readable.
     *
     * It is also why .sc-cast-dialog is 860px. Two 400px cards plus the gap and
     * the dialog's padding need 836 of content, and at the old 790 the popup
     * would have dropped to a single card per row. */
    flex: 1 1 400px;
    max-width: 600px;
}

/* The picture at size. 3:4 because that is what the sketches are drawn at --
   see aiImageStyles() -- so a generated portrait fills the frame rather than
   being letterboxed inside it. An uploaded photograph of another shape is
   cropped to fit by object-fit rather than squashed. */
.sc-card-face {
    flex: 0 0 111px;
    width: 111px;

    /* THE FRAME IS ITS OWN HEIGHT, NOT THE CARD'S
     *
     * align-self, and it is the whole fix. .sc-card is a flex row and the
     * default align-items is stretch, so this item -- which has a definite
     * WIDTH and an auto height -- was being stretched to whatever the card
     * happened to be. That also silently cancelled the aspect-ratio below: the
     * ratio only sizes a box whose other dimension is auto, and stretching had
     * made the height definite.
     *
     * So a character with a lot written about them got a taller card, a taller
     * card got a taller frame, and object-fit: cover then threw away the sides
     * of the picture to fill it. On a 250px card that is a third of the width
     * of the portrait gone -- and it got worse the more the author wrote, which
     * is the opposite of what it should do.
     *
     * With this the frame is 111 x 166 whatever the card does, which is the
     * max-height the picture needed: it cannot grow down the card any more, and
     * a tall card simply has space under the frame.
     *
     * 2:3 RATHER THAN 3:4
     *
     * 0.672 is the median of the 258 character pictures on this box, because
     * that is what aiImageStyles() generates -- 168 x 250. The frame was 3:4,
     * which is close but not the same, and the difference was 18px off the top
     * and bottom of every generated sketch for no reason. Matching it exactly
     * means a sketch is shown whole.
     *
     * Uploaded photographs are still cropped, and must be -- they run from 0.65
     * to 1.34, so no single frame suits them all. cover centres the crop, which
     * is the best a fixed frame can do with a landscape photograph. */
    align-self: flex-start;
    aspect-ratio: 2 / 3;

    border-radius: 6px;
    background: #e2dedb;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}

.sc-card-face img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    cursor: zoom-in;
}

.sc-card-face i {
    font-size: 26px;
    color: #b3aca6;
}

.sc-card-body {
    min-width: 0;
    /* or the clamped text below refuses to shrink */
    flex: 1;
}

.sc-card-name {
    margin: 0;
    font-size: 14px;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--color-text-body, #2c3e50);
}

.sc-card-sub {
    margin: 1px 0 7px;
    font-size: 12px;
    color: var(--text-muted, #8a8a8a);
}

.sc-card-block {
    margin-bottom: 6px;
}

.sc-card-label {
    display: block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--primary, #06798e);
}

/* Clamped rather than cut in the JavaScript, so every card is the same height
   whatever was written and the whole sentence is still in the page for anyone
   who selects it.

   THREE LINES, NOT TWO

   At two, a want that ran to a sentence and a half was cut mid-clause on every
   card -- the reader got the setup and not the point of it. Three is the line
   that makes most of these whole, and it costs about 18px a block: a card
   roughly 70px taller in exchange for four fields that finish their thought.

   It is the same trade the wider card made, in the other direction. There is no
   value in fitting six characters on a screen if none of them can be read. */
.sc-card-text {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 12.5px;
    line-height: 1.4;
    color: var(--text-soft, #555);
}

.sc-card-none {
    margin: 4px 0 0;
    font-size: 12.5px;
    font-style: italic;
    color: var(--text-muted, #8a8a8a);
}

/* The tabs stay put while the cards scroll.

   Scoped to the popup, where .dialogBoxContents is the scroll container and
   70vh of cards runs well past the bar. Without this, switching tab after
   reading to the bottom of Supporting means scrolling all the way back up to
   reach the control.

   Not applied to the panel generally: on a page the tabs scroll with
   everything else, which is right, and a sticky bar there would need to know
   about the site header it would otherwise slide under. */
.sc-cast-dialog .sc-tabs {
    position: sticky;
    top: 0;
    z-index: 1;
    background: #fff;
    padding-top: 2px;
}

/* What they look like, under the facts line and above the drama.

   Unlabelled, so it has to read as description on its own: a shade darker than
   the profession/age/gender line above it and set apart from it, but quieter
   than the labelled blocks below, which are the part somebody is scanning for.

   Clamped to two lines like those blocks, for the same reason -- every card the
   same height whatever was written, and the whole sentence still in the page
   for anyone who selects it. Appearance is often the longest thing the
   breakdown writes, so without this one character could be twice the height of
   the one beside them. */
.sc-card-look {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: 0 0 7px;
    font-size: 12.5px;
    line-height: 1.4;
    color: var(--text-soft, #555);
}

/* A card you can open ─────────────────────────────────────────────────────

   On a page the card behaves like the compact row it replaces: it opens the
   character's record, so it says so with a cursor and a lift on hover. In the
   cast popup it opens nothing -- see storyCharacterReadOnly -- and
   .sc-card--static takes both away, because a card that lights up under the
   pointer and then does nothing when pressed is worse than one that never
   invited the press. */
.sc-card {
    position: relative;
    /* for the remove control below */
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.sc-card:hover {
    border-color: var(--primary, #06798e);
    box-shadow: 0 1px 6px rgba(0, 0, 0, .07);
}

.sc-card--static,
.sc-card--static:hover {
    cursor: default;
    border-color: var(--border, #e6e3e0);
    box-shadow: none;
}

/* Off the list, without opening the record first.

   Hidden until the card is hovered, like the compact row's, so a page of cards
   is a page of characters rather than a page of delete buttons. Top right,
   clear of the text column, and over the card's own padding rather than
   inside the body -- a control in the flow would push the prose around. */
.sc-card-x {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 22px;
    height: 22px;
    padding: 0;
    border: none;
    border-radius: 4px;
    background: none;
    color: var(--text-muted, #b3aca6);
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition: opacity .15s ease, color .15s ease, background .15s ease;
}

.sc-card:hover .sc-card-x {
    opacity: 1;
}

.sc-card-x:hover {
    background: #f6eceb;
    color: var(--danger, #e85347);
}

/* A touch screen has no hover, so the control would never appear at all. */
@media (hover: none) {
    .sc-card-x {
        opacity: 1;
    }
}

/* ── Import from another script (js/storyimport.js, Ben 2026-10-10) ──
   Inside a SweetAlert, for characters and locations alike. */
.si-note {
    margin: 0 0 10px;
    font-size: 14px;
    text-align: left;
}

.si-source {
    width: 100%;
    padding: 7px 8px;
    font-size: 15px;
    border: 1px solid var(--border, #dbdfea);
    border-radius: 6px;
}

.si-list {
    max-height: 52vh;
    overflow-y: auto;
    margin-top: 12px;
    text-align: left;
}

.si-empty {
    margin: 10px 0;
    font-size: 14px;
    opacity: .7;
}

.si-group + .si-group {
    margin-top: 14px;
}

.si-group-title {
    margin: 0;
    font-weight: 700;
    font-size: 15px;
}

.si-group-title span {
    font-weight: 400;
    opacity: .6;
}

.si-group-note {
    margin: 2px 0 6px;
    font-size: 13px;
    opacity: .7;
}

.si-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 4px;
    border-radius: 6px;
    font-size: 15px;
    cursor: pointer;
}

.si-row:hover {
    background: var(--bg-light, #f5f6fa);
}

.si-row-here {
    cursor: default;
    opacity: .55;
}

.si-row-here:hover {
    background: none;
}

.si-pic {
    flex: none;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    object-fit: cover;
}

.si-pic-wide {
    width: 54px;
    height: 32px;
    border-radius: 4px;
}

.si-pic-none {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-light, #f0f1f5);
    color: #8a94a6;
    font-size: 14px;
}

.si-name em {
    font-style: normal;
    font-size: 13px;
    opacity: .65;
    margin-left: 4px;
}
