/* css/ai-images.css
 *
 * The sketch dialog: asking for pictures, and choosing between them.
 *
 * Everything here is .ai-sk-, inside a SweetAlert popup that carries
 * .ai-sk-popup, so none of it can reach the page behind. The dialog it is
 * launched from -- popup/storyCharacter.php -- is .sc- and untouched.
 */

.ai-sk-popup {
    font-family: var(--font-sans);
}

.ai-sk-form {
    text-align: left;
    max-width: 580px;
    margin: 0 auto;
}

.ai-sk-label {
    display: block;
    margin: 14px 0 4px;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--overline);
}

/* Worn by the selects and by the one text input, which wants to line up with
   them rather than sit at whatever width the browser thinks an input is. */
.ai-sk-select {
    width: 100%;
    padding: 8px 10px;
    font-size: 15px;
    font-family: inherit;
    color: var(--text-dark);
    background: var(--bg-white);
    border: 1px solid var(--border);
    border-radius: 4px;
}

/* The colours only. Everything about the SIZE of this box -- padding, font,
   line height, border -- is set by the .grow-wrap pair above, because the
   hidden mirror has to match it exactly. Setting any of them here would set
   them on the textarea alone and open the gap that rule exists to close. */
.ai-sk-prompt {
    width: 100%;
    color: var(--text-dark);
    background: var(--bg-light);
}

.ai-sk-hint {
    margin-top: 10px;
    font-size: 13px;
    line-height: 1.4;
    color: var(--text-muted);
}

/* The auto-growing box, carried into this dialog.

   .grow-wrap is defined in css/dashboard.css, which does NOT load on every page
   this dialog can open from -- the editor and the read-only script page have
   character.js without it. So the whole mechanism is restated here, scoped to
   the popup, and the dialog behaves the same wherever it is opened.

   HOW IT WORKS, AND THE ONE RULE

   The wrapper is a grid with two things in the same cell: the textarea, and an
   ::after carrying a hidden copy of the same text. The cell takes the height of
   the taller, so the box grows as the text does. That holds ONLY while the two
   are laid out identically -- same font, same size, same line height, same
   padding, same border. css/modal.css carries the same warning for the same
   reason: when they drifted by 4px of padding the mirror wrapped sooner and the
   box jumped as you typed.

   Which is why they are set together, in one rule, and .ai-sk-prompt no longer
   sets any of them on its own. */
.ai-sk-popup .grow-wrap {
    display: grid;
}

.ai-sk-popup .grow-wrap::after {
    content: attr(data-replicated-value) " ";
    white-space: pre-wrap;
    visibility: hidden;
}

.ai-sk-popup .grow-wrap > textarea {
    resize: none;
    overflow: hidden;
}

.ai-sk-popup .grow-wrap > textarea,
.ai-sk-popup .grow-wrap::after {
    grid-area: 1 / 1 / 2 / 2;
    padding: 10px;
    font-family: inherit;
    font-size: 14px;
    line-height: 1.45;
    border: 1px solid var(--border);
    border-radius: 4px;
}

/* Something that happened and is worth reading -- a refusal, or two of three
   coming back. Not an error style: most of what lands here is ordinary. */
.ai-sk-note {
    margin: 0 0 12px;
    padding: 10px 12px;
    font-size: 14px;
    line-height: 1.4;
    color: var(--text-dark);
    background: var(--bg-light);
    border-left: 3px solid var(--warning);
    border-radius: 3px;
    text-align: left;
}

.ai-sk-wait {
    margin: 10px 0 0;
    font-size: 15px;
    color: var(--text-soft);
}

/* The price, said before anything is drawn. Sits directly under the count it
   is the price OF, and is the only thing in the form at full text weight --
   everything else there is a label or a hint. */
.ai-sk-cost {
    margin: 8px 0 0;
    padding: 8px 10px;
    font-size: 15px;
    color: var(--text-dark);
    background: var(--bg-light);
    border-radius: 4px;
}

.ai-sk-short {
    color: var(--danger);
    font-weight: 600;
}

/* The staff model picker, marked as the bench tool it is: a dashed rule and a
   lock, so nobody mistakes it for part of the feature when they see a
   screenshot of it. */
.ai-sk-staff {
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px dashed var(--border);
}

.ai-sk-staff .ai-sk-label {
    color: var(--danger);
}

.ai-sk-staff .ai-sk-label i {
    margin-right: 5px;
}

/* Framing and Facing, side by side. They are one decision about the photograph
   and take a line between them rather than two -- the form is already four
   controls tall before the model picker. */
.ai-sk-pair {
    display: flex;
    gap: 12px;
}

.ai-sk-pair > div {
    flex: 1 1 0;
    min-width: 0;
}

/* "The three you have are kept." Quiet, and not a warning: it is reassurance,
   and styling it like the amber note above would make keeping sketches sound
   like something to worry about. */
.ai-sk-keep {
    margin: 8px 0 0;
    font-size: 13px;
    line-height: 1.4;
    color: var(--text-soft);
}

.ai-sk-keep i {
    margin-right: 5px;
    color: var(--text-muted);
}

/* ---- the choice -------------------------------------------------------- */

.ai-sk-wide {
    width: min(820px, 96vw);
}

/* Three across where there is room, and as many as fit where there is not.
   auto-fit rather than a fixed three: one sketch should not sit in a third of
   the dialog with two empty columns beside it.

   The height is capped and the grid scrolls inside it. Sketches accumulate --
   that is the point of keeping them -- and by the second or third batch an
   uncapped dialog runs off the bottom of the screen, taking Draw more and Done
   with it. 58vh leaves the title above and the buttons below on a laptop. */
.ai-sk-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 16px;
    margin: 6px 0 4px;
    max-height: 58vh;
    overflow-y: auto;
    /* Room for the scrollbar, so the last column is not clipped by it. */
    padding-right: 4px;
}

/* Once there are more than four, tiles are allowed to get smaller -- five
   across instead of three on a wide dialog. The count is what changes, not the
   layout: auto-fill still decides how many fit. */
.ai-sk-grid--dense {
    grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
    gap: 12px;
}

.ai-sk-grid--dense .ai-sk-card figcaption {
    padding: 6px;
}

/* At that size a full button label does not fit, so the caption becomes the
   two controls and nothing else -- the picture is the label. */
.ai-sk-grid--dense .ai-sk-use {
    font-size: 13px;
    padding: 5px 6px;
}

.ai-sk-card {
    position: relative;
    margin: 0;
    background: var(--bg-light);
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
}

/* The one the character is actually wearing. Marked rather than merely
   implied: a gallery of eight sketches that does not say which is in use makes
   the writer go and look at the card behind to find out. */
.ai-sk-card--current {
    border-color: var(--primary);
    box-shadow: 0 0 0 2px var(--primary-dim);
}

.ai-sk-flag {
    position: absolute;
    top: 6px;
    left: 6px;
    padding: 2px 7px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: #fff;
    background: var(--primary);
    border-radius: 3px;
}

/* Where the Use button would be, on the one already in use. Same footprint, so
   the tiles stay the same height whichever of them is current. */
.ai-sk-using {
    flex: 1 1 auto;
    padding: 7px 10px;
    font-size: 14px;
    color: var(--text-muted);
}

.ai-sk-card img {
    display: block;
    cursor: zoom-in;
    width: 100%;
    height: auto;
    /* The portraits come back 2:3 and all three are the same shape, so nothing
       needs cropping -- but a model that returns something else must not be
       allowed to stretch the row it is in. */
    aspect-ratio: 2 / 3;
    object-fit: cover;
    background: var(--btn-bg-light);
}

/* No gap. The Use button stretches to fill the row, so the only thing a gap
   does here is push the two icons apart from each other and from the edge --
   and both of them already carry 6px of their own padding, which is the space
   that was wanted. 8px on top of that was twice as much as it looked. */
.ai-sk-card figcaption {
    display: flex;
    align-items: center;
    gap: 0;
    padding: 8px;
}

/* The one in use has no button, so nothing stretches and the two icons would
   fall to the left -- out of line with every other tile in the grid, where the
   stretched Use This pushes them right. Sending them to the end puts the
   download and the bin in the same place on every card, which is what makes a
   wall of sketches scannable. */
.ai-sk-card--current figcaption {
    justify-content: flex-end;
}

/* min-width:0 with flex:1 1 auto, so the button gives way before it wraps.
   A flex item will not shrink below its content by default, which is how two
   words plus two icons managed to need several lines in a dense tile.

   justify-content, NOT text-align. .btn in css/global.css is display:inline-flex
   and sets align-items but no justify-content -- so the label is a flex item
   that sits at the start, and on a button stretched by flex:1 1 auto that
   leaves it against the left edge with all the free space to its right.
   text-align does nothing to a flex item. */
.ai-sk-use {
    flex: 1 1 auto;
    min-width: 0;
    justify-content: center;
    background: var(--primary);
    color: #fff;
    border: 0;
    border-radius: 4px;
    padding: 7px 10px;
    font-family: inherit;
    font-size: 14px;
    white-space: nowrap;
    cursor: pointer;
}

.ai-sk-use:hover {
    filter: brightness(1.08);
}

/* The bin is deliberately quiet: it sits beside the button somebody actually
   came here to press, and a red icon at the same weight would compete with it.
   It colours on hover, where the intent is unambiguous. */
/* 4px left and right rather than 6. The space between the two icons is the sum
   of their facing paddings, so trimming the horizontal pair brings them
   together without making either a smaller target vertically. Both icons carry
   the same value -- they are a matched pair and one of them padded differently
   reads as a mistake. */
.ai-sk-bin {
    flex: none;
    background: transparent;
    border: 0;
    padding: 6px 4px;
    font-size: 15px;
    color: var(--text-muted);
    cursor: pointer;
}

.ai-sk-bin:hover {
    color: var(--danger);
}

/* The download, beside the bin and matching it exactly.
 *
 * Same size, same padding, same muted grey, for the same reason the bin is
 * quiet: the thing a writer came to this dialog to press is "Use this one",
 * and two coloured icons either side of it would compete with the button that
 * matters. It colours on hover, where the intent is unambiguous.
 *
 * An <a> needs three declarations a <button> does not -- inline-flex to sit on
 * the line with its neighbours, no underline, and an explicit colour, since a
 * link would otherwise take the document's. */
.ai-sk-get {
    display: inline-flex;
    align-items: center;
    flex: none;
    padding: 6px 4px;
    font-size: 15px;
    color: var(--text-muted);
    text-decoration: none;
    cursor: pointer;
}

.ai-sk-get:hover {
    color: var(--primary);
    text-decoration: none;
}

/* ---- are you sure, on the card ------------------------------------------ */

/* Over the one sketch it is about, with the rest of the wall still visible
   behind it. A Swal would have replaced the whole gallery to ask about one
   tile -- see aiSketchDelete(), which says why that read so badly.
   .ai-sk-card is position:relative already, for the "In use" flag.

   Dark enough to be plainly a question and not part of the card, and it covers
   the picture on purpose: the thing being deleted should not still be sitting
   there looking available. */
.ai-sk-sure {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px;
    background: rgba(15, 18, 28, .88);
    text-align: center;
    cursor: default;
}

.ai-sk-sure-q {
    margin: 0;
    color: #fff;
    font-size: 14px;
    font-weight: 700;
    line-height: 1.25;
}

.ai-sk-sure-note {
    margin: 0;
    color: rgba(255, 255, 255, .75);
    font-size: 12px;
    line-height: 1.35;
}

.ai-sk-sure-btns {
    display: flex;
    gap: 6px;
    margin-top: 2px;
}

/* Keep first and Delete second, left to right. The safe one is where a hand
   lands first, and the destructive one is never under a pointer that was
   already moving towards the bin it just pressed. */
/* 9px sides, not 12. Two buttons side by side inside a tile that the dense
   grid can squeeze well under 150px -- at 12px the pair no longer fitted on
   one line and "Delete" broke across two. nowrap as well, so a narrower tile
   than any we have today shrinks the gap between them rather than the words. */
.ai-sk-sure-no,
.ai-sk-sure-yes {
    border: 0;
    border-radius: 4px;
    padding: 6px 9px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

.ai-sk-sure-no {
    background: rgba(255, 255, 255, .92);
    color: var(--text-dark, #364a63);
}

.ai-sk-sure-yes {
    background: var(--danger, #e85347);
    color: #fff;
}

.ai-sk-sure-no:hover,
.ai-sk-sure-yes:hover {
    filter: brightness(1.08);
}

/* While the server is answering. Both go quiet rather than vanishing, so the
   card does not change shape under the pointer mid-press. */
.ai-sk-sure button:disabled {
    opacity: .55;
    cursor: default;
}

/* ---- the way in, on the character dialog -------------------------------- */

/* Under the portrait, in a column fixed at 140px. Everything here is about
   staying on one line in that width: the label is short, the text does not
   wrap, and what will not fit is trimmed rather than allowed to push the
   button taller than the one above it. */
/* NO top margin, and a bottom one.
 *
 * The 8px on top was doubling up with the 3px gap on .sc-portrait, which is
 * the flex column both this and the picture sit in -- 11px of air between a
 * button and the thing it acts on, which made them read as two separate
 * controls rather than one thing and its verb. The gap alone is the space
 * wanted, and dropping this gives 8px back to a dialog that was too tall.
 *
 * The bottom margin stays: this is the LAST thing in its column, and the
 * portrait frame is 2:3 now rather than square, so the button can end up level
 * with the first heading in the section below .sc-top -- two unrelated things
 * almost touching across a gap that reads as a mistake. */
/* TWO CLASSES, AND THE 13px IS THE REASON.
 *
 * .modal360-content button in css/modal.css sets every button in a dialog to
 * 16px, and at (0,1,1) it outranked the single class here whatever the load
 * order -- so this button has been rendering at 16px since the day it was
 * written, and nobody could see it because there is nothing beside it to
 * compare with.
 *
 * What made it visible was the column it sits in. The label is nowrap, and
 * .sc-portrait had min-width:auto, so the widest label pushed the whole column
 * -- and the portrait frame with it -- as wide as the text needed: 169px on a
 * character with no sketches yet ("Sketch Character") against 136px on one
 * with some ("Sketches (9)"). The same dialog, two sizes of picture, decided
 * by a string. See .sc-portrait in css/character.css for the other half. */
.sc-dialog .sc-sketch-btn {
    display: block;
    width: 100%;
    margin-bottom: 10px;
    padding: 7px 8px;
    font-family: inherit;
    font-size: 13px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--text-dark);
    background: var(--btn-bg-light);
    border: 1px solid var(--border);
    border-radius: 4px;
    cursor: pointer;
}

.sc-sketch-btn:hover {
    background: var(--primary-dim);
}

.sc-sketch-btn i {
    margin-right: 5px;
    color: var(--primary);
}

/* ══════════════════════════════════════════════
   THE STYLE SAMPLES
   ══════════════════════════════════════════════ */

/* The dropdown and the way to see inside it, on one line.
   The select takes what is left: it holds two or three words and never needed
   a whole row, and the button has a fixed appetite. */
.ai-sk-style-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
}

.ai-sk-style-row .ai-sk-select {
    flex: 1 1 auto;
    min-width: 0;
    margin-bottom: 0;
}

/* Quiet. It sits beside the first field of a form whose subject is the Draw
   button at the bottom, and a second filled button up here would argue with
   it. */
.ai-sk-samples-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    border: 1px solid var(--border, #dbdfea);
    border-radius: 6px;
    background: #fff;
    color: var(--text-soft, #526484);
    font-family: inherit;
    font-size: 13px;
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease, color .15s ease;
}

.ai-sk-samples-btn:hover {
    border-color: var(--gold, #c9a84c);
    background: #fffbea;
    color: var(--text-dark, #364a63);
}

.ai-sk-samples-btn i {
    font-size: 14px;
}

/* ── the dialog ── */

.ai-sk-samp-popup {
    text-align: left;
}

.ai-sk-samp-tabs {
    display: flex;
    gap: 4px;
    border-bottom: 2px solid var(--border, #dbdfea);
    margin-bottom: 14px;
}

/* Tabs that sit ON the rule rather than above it, so the lit one reads as the
   front sheet of two. -2px pulls its own border over the container's. */
.ai-sk-samp-tab {
    padding: 9px 24px;
    margin-bottom: -2px;
    border: 0;
    border-bottom: 3px solid transparent;
    background: none;
    font-family: inherit;
    /* 18px. These were 14 and sat under a dialog title at 24 looking like a
       caption for it rather than the switch between two sets of pictures --
       which, with the description gone, is the only control in here. */
    font-size: 18px;
    font-weight: 600;
    color: var(--text-muted, #8094ae);
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease;
}

.ai-sk-samp-tab:hover {
    color: var(--text-dark, #364a63);
}

.ai-sk-samp-tab.is-on {
    color: var(--text-dark, #364a63);
    border-bottom-color: var(--gold, #c9a84c);
}

/* -3px now, to cover the 3px rule the lit tab draws. */
.ai-sk-samp-tabs {
    border-bottom-width: 3px;
}

/* auto-fill at 150px: six across in an 860px dialog, dropping to three and
   then two as the window narrows, with the eleventh simply starting a row. */
.ai-sk-samp-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
}

.ai-sk-samp-cell {
    margin: 0;
}

.ai-sk-samp-cell img {
    display: block;
    width: 100%;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border: 1px solid var(--border, #dbdfea);
    border-radius: 6px;
    background: var(--bg-light, #f5f6fa);
    cursor: zoom-in;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.ai-sk-samp-cell img:hover {
    border-color: var(--gold, #c9a84c);
    box-shadow: 0 6px 18px rgba(0, 0, 0, .12);
}

.ai-sk-samp-cell figcaption {
    padding-top: 5px;
    text-align: center;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-soft, #526484);
}


/* ══════════════════════════════════════════════
   QUICK SKETCH
   One sketch for every character at once -- the button on the Characters
   panel and its dialog. See aiQuickSketchOpen() in js/ai-images.js.
   ══════════════════════════════════════════════ */

/* On the Characters panel, above the list. The same look as the Sketch button
   in the character dialog, because it is the same kind of act -- but its own
   width, left-aligned: across a wide panel a full-width button reads as a
   banner rather than as a control. */
.sc-quick-sketch {
    display: inline-flex;
    align-items: center;
    flex: none;
    width: auto;
    margin: 0;
    padding: 6px 12px;
    white-space: nowrap;
    font-family: inherit;
    font-size: 13px;
    color: var(--text-dark);
    background: var(--btn-bg-light);
    border: 1px solid var(--border);
    border-radius: 4px;
    cursor: pointer;
}

.sc-quick-sketch:hover {
    background: var(--primary-dim);
}

/* The line the button sits on: beside the SmartType dropdown where the panel
   is wide, alone where it is not. Wraps rather than squeezing, so a narrow
   window puts the button under the dropdown instead of crushing either. */
.sc-tools-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    margin: 4px 2px 10px;
}

/* In the row the dropdown keeps its own cap and loses the bottom margin it
   carries when it stands alone. */
.sc-tools-row .sc-untracked-select {
    flex: 1 1 240px;
    margin: 0;
}

.sc-quick-sketch i {
    margin-right: 5px;
    color: var(--primary);
}

.ai-qs-form {
    max-width: 620px;
}

.ai-qs-modes {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 15px;
    color: var(--text-dark);
}

.ai-qs-modes label {
    display: flex;
    align-items: center;
    gap: 7px;
    cursor: pointer;
}

.ai-qs-form .ai-sk-keep[hidden] {
    display: none;
}

/* The checklist. Capped and scrolling, so a large cast does not push the
   price and the buttons off the bottom of the dialog. */
.ai-qs-list {
    margin-top: 10px;
    max-height: 260px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: 6px;
}

.ai-qs-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 10px;
    border-top: 1px solid var(--border);
    cursor: pointer;
    text-align: left;
}

.ai-qs-row:first-child {
    border-top: 0;
}

.ai-qs-row:hover {
    background: var(--bg-light);
}

.ai-qs-row img,
.ai-qs-noimg {
    flex: none;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--bg-light);
}

.ai-qs-noimg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
    font-size: 14px;
}

.ai-qs-who {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}

.ai-qs-who b {
    font-size: 14px;
    color: var(--text-dark);
}

.ai-qs-who span {
    font-size: 12px;
    color: var(--text-soft);
}

/* Little description: drawn anyway, and said so. */
.ai-qs-thin {
    flex: none;
    color: var(--warning);
}

/* Progress and the summary: a face per character as it arrives. */
.ai-qs-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 12px;
    margin: 10px 0;
}

.ai-qs-tile {
    margin: 0;
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
    background: var(--bg-light);
}

.ai-qs-pic {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 2 / 3;
    font-size: 22px;
    color: var(--text-muted);
}

.ai-qs-pic img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.ai-qs-tile figcaption {
    padding: 5px 6px;
    font-size: 12px;
    line-height: 1.25;
    text-align: center;
}

.ai-qs-tile figcaption b {
    display: block;
    color: var(--text-dark);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ai-qs-tile figcaption span {
    display: block;
    color: var(--text-soft);
}

.ai-qs-tile.is-drawing {
    border-color: var(--primary);
    box-shadow: 0 0 0 2px var(--primary-dim);
}

.ai-qs-tile.is-failed .ai-qs-pic,
.ai-qs-tile.is-skipped .ai-qs-pic {
    opacity: .55;
}
