/*
 * inline-edit.css — click-to-edit description fields on quote/job/invoice
 * detail pages (components/detail/{entity}_description.html).
 *
 * The whole point of this sheet: the read-only block and the Tiptap editable
 * MUST share one box so switching to edit does not move or re-wrap a single
 * character. Both carry .inline-edit-field; the display border is transparent
 * so it reserves the same 2px the editable's visible border occupies. Geometry
 * (font, line-height, padding, width, wrap) is identical in both states.
 *
 * Both states now hold the SAME markup (paragraphs, lists, inline <img>), so
 * every rule for that content is written against .inline-edit-field and applies
 * to display and edit alike — which is what keeps them pixel-identical.
 *
 * HTML: components/detail/entity_description.html
 * JS:   static/js/controllers/esm/inline_edit_controller.js
 */

/* Shared text box — identical in display and edit states. The horizontal
   padding + border would inset the text from the "Description" heading, so
   negative margins bleed the BOX outward by that exact amount instead: the
   text stays flush with the heading and the box edge absorbs the inset,
   sitting inside the card's surrounding padding (24px available, 12px used). */
.inline-edit-field {
    --inline-edit-inset: calc(0.625rem + 2px);  /* h-padding + border */
    display: block;
    width: calc(100% + 2 * var(--inline-edit-inset));
    box-sizing: border-box;
    margin: 0 calc(-1 * var(--inline-edit-inset));
    padding: 0.5rem 0.625rem;       /* tight: box hugs the text, lines run wide */
    border: 2px solid transparent;  /* same width both states → no shift */
    border-radius: 8px;
    font-family: inherit;
    font-size: 16px;                /* iOS-safe; matches form-control-mobile */
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
    background: transparent;
    color: inherit;
}

/* The editable state. Tiptap stamps .inline-edit-field onto the ProseMirror
   element itself (editorProps.attributes) rather than a wrapper, so it inherits
   the shared geometry above and only needs the visible frame added — exactly
   what the <textarea> it replaced needed. Scoped by .rich-description-mount so
   nothing else can pick up a contenteditable frame. */
.rich-description-mount .inline-edit-field {
    border-color: var(--border-light, #ced4da);
    background: #fff;
    min-height: 44px;               /* touch target for an empty description */
}

.rich-description-mount .inline-edit-field:focus {
    outline: none;
    border-color: var(--bs-primary, #0d6efd);
}

/* Paragraph rhythm, applied to BOTH states from the one selector so display and
   edit stay pixel-identical. Bootstrap's 1rem <p> margin is far too airy for a
   field this size, and the trailing margin would pad dead space below the last
   line — which in the editor reads as a clickable region that is not text. */
.inline-edit-field p {
    margin: 0 0 0.5rem;
}
.inline-edit-field > :last-child {
    margin-bottom: 0;
}
.inline-edit-field ul,
.inline-edit-field ol {
    margin: 0 0 0.5rem;
    padding-left: 1.35rem;
}

/* Inline images. Constrained to the field width so a phone photo cannot blow out
   the card, and block-level so it never sits awkwardly mid-sentence — the same
   rendering the public page, PDF and email produce, so what the tradie composes
   is what the client sees. */
.inline-edit-field img {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 0.5rem 0;
    border-radius: 6px;
}

/* Resize wrapper. Editor-only: the description is stored and sent as a plain
   <img style="width:N%">, and this box exists solely to give the drag handle a
   corner to sit on. Without an explicit width it shrinks to the picture, so the
   grip lands on the photo's edge rather than out in the empty field. */
.rd-image {
    position: relative;
    display: block;
    width: fit-content;
    max-width: 100%;
    margin: 0.5rem 0;
}

.rd-image img {
    margin: 0;    /* the wrapper owns the spacing now */
}

/* Corner grips, one per corner so the nearest one is always within reach.
   Hidden until the image is hovered or selected, so a description full of
   photos is not also full of blue dots. Tapping an image selects the node,
   which is what surfaces the handles on a phone — there is no hover there.

   Round, not square: a filled square reads as a crop mark or a broken image
   placeholder, while a dot on a corner is the near-universal resize idiom. */
.rd-image__handle {
    position: absolute;
    width: 13px;
    height: 13px;
    border: 2px solid #fff;
    border-radius: 50%;
    background: var(--bs-primary, #0d6efd);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: opacity 0.12s ease-in-out;
    /* Without this the browser claims the gesture for scrolling and the
       pointermove events never arrive on touch. */
    touch-action: none;
}

/* A finger-sized target without a finger-sized dot: the grip stays 13px to the
   eye while the pointer sees a 33px box. Four visible dots that large would
   swamp a small photo. */
.rd-image__handle::before {
    content: '';
    position: absolute;
    inset: -10px;
}

/* Straddling the corner rather than sitting inside it, so the dot marks the
   picture's edge instead of covering the content just in from it. */
.rd-image__handle--nw { top: 0; left: 0; transform: translate(-50%, -50%); cursor: nwse-resize; }
.rd-image__handle--ne { top: 0; right: 0; transform: translate(50%, -50%); cursor: nesw-resize; }
.rd-image__handle--sw { bottom: 0; left: 0; transform: translate(-50%, 50%); cursor: nesw-resize; }
.rd-image__handle--se { bottom: 0; right: 0; transform: translate(50%, 50%); cursor: nwse-resize; }

.rd-image:hover .rd-image__handle,
.rd-image.ProseMirror-selectednode .rd-image__handle,
.rd-image--resizing .rd-image__handle {
    opacity: 1;
}

/* ProseMirror marks a clicked image as the selected node; without a visual cue
   there is no way to tell what Backspace is about to delete. The class lands on
   the node view's own element, which is the wrapper above.

   A resize in progress gets the same frame, in the same colour as the grips: it
   is the edge the drag is moving, so showing it is what makes the new size
   legible before the finger lifts. Selected and resizing look alike on purpose
   — both mean "this picture is what you are acting on". */
.rich-description-mount .inline-edit-field .rd-image.ProseMirror-selectednode,
.rich-description-mount .inline-edit-field .rd-image--resizing {
    outline: 2px solid var(--bs-primary, #0d6efd);
    outline-offset: 2px;
}

/* Add-image menu, iOS variant: Camera + Library collapse into one "New photo".
   WebKit always presents its own Photo Library / Take Photo / Choose Files
   sheet for an image <input> and nothing suppresses it (`capture` forces
   camera-only, with no library-only counterpart), so listing both here asks the
   user twice. "Choose existing" is Chippie's own picker, not the OS's, so it
   survives on every platform. Flag: static/js/platform-flags.js. */
.rd-image-source--ios {
    display: none;
}

.is-ios .rd-image-source--menu {
    display: none;
}

.is-ios .rd-image-source--ios {
    display: block;
}

/* "Choose existing" strip: the entity's current photos, offered back for inline
   reuse. One row that scrolls sideways rather than a wrapping grid, so opening
   it never pushes Save off the screen on a phone. */
.rich-description-picker {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    overflow-x: auto;
    margin-top: 0.5rem;
    padding-bottom: 0.25rem;
    -webkit-overflow-scrolling: touch;
}

.rich-description-picker__thumb {
    flex: 0 0 auto;
    width: 64px;
    height: 64px;
    padding: 0;
    border: 2px solid transparent;
    border-radius: 6px;
    background: none;
    overflow: hidden;
}

.rich-description-picker__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.rich-description-picker__thumb:hover,
.rich-description-picker__thumb:focus-visible {
    border-color: var(--bs-primary, #0d6efd);
    outline: none;
}

/* Heading row: "Description" label on the left, pencil on the right. The
   pencil lives here (not over the text) so it costs the description zero
   horizontal space. */
.inline-edit-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.25rem;
}

/* Edit affordance: pencil glyph + "Edit" label. The icon alone read as
   decoration to some users, so the word carries the action while the glyph
   keeps it scannable. Styled as a light pill (subtle outline, tinted hover)
   rather than a bare link — a clear, finger-sized target. The negative
   vertical margin cancels the padding out of layout so the heading row stays
   label-height (the Amount heading must not sit taller than the Status label
   beside it). */
.inline-edit-pencil {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    color: var(--bs-primary, #0d6efd);
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1;
    text-decoration: none;
    padding: 0.3rem 0.6rem;
    margin-top: -0.25rem;
    margin-bottom: -0.25rem;
    border: 1px solid var(--bs-primary-border-subtle, #9ec5fe);
    border-radius: 999px;
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

/* Icon a touch larger than the label so the pair stays legible. */
.inline-edit-pencil i {
    font-size: 0.95rem;
    line-height: 1;
}

.inline-edit-pencil:hover,
.inline-edit-pencil:focus {
    color: #fff;
    background: var(--bs-primary, #0d6efd);
    border-color: var(--bs-primary, #0d6efd);
    text-decoration: none;
}

.inline-edit-pencil:focus-visible {
    outline: 2px solid var(--bs-primary, #0d6efd);
    outline-offset: 2px;
}

/* Bottom toolbar: mic + enhance trigger on the top line, Cancel/Save pinned
   top-right, and the enhance prompt/undo rows dropping to their own full-width
   line below. flex-wrap + per-item `order` drive that without restructuring the
   shared enhance include. */
.inline-edit-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0.5rem;
    margin-top: 0.5rem;
}

/* Lift the enhance include's children (trigger button + prompt/undo rows) into
   the toolbar's flex flow so the prompt row can span a full line of its own
   instead of being crushed into a narrow cell beside Save/Cancel. The container
   stays in the DOM (display:contents only drops its box), so ai_enhance.js's
   closest()/querySelector() wiring is unaffected. */
.inline-edit-toolbar .ai-enhance-container {
    display: contents;
}

/* The shared enhance include positions its trigger button absolutely for the
   modal overlay (Bootstrap's .position-absolute utility is `!important`, and
   the offset is an inline style). Inline-edit needs it in normal flow beside
   the mic, so override both with `!important`. */
.inline-edit-toolbar .ai-enhance-btn {
    position: static !important;
    top: auto !important;
    right: auto !important;
    order: 0;
}

/* Cancel/Save stay on the top line, pushed to the far right. */
.inline-edit-actions {
    order: 1;
    margin-left: auto;
    display: flex;
    gap: 0.5rem;
    flex-shrink: 0;
}

/* Enhance prompt + undo rows take their own full-width line below the toolbar. */
.inline-edit-toolbar .ai-enhance-prompt-row,
.inline-edit-toolbar .ai-enhance-undo-row {
    order: 2;
    flex: 0 0 100%;
    width: 100%;
}

/* ---------------------------------------------------------------------------
 * Price block (components/detail/inline_price.html) — the unified amount +
 * line-items editor. JS: controllers/esm/inline_price_controller.js
 * ------------------------------------------------------------------------- */

/* Persistent "+$200 above quoted" differentiator under the amount. Renders in
   display mode whenever the live amount diverges from the accepted quote. */
.price-variance-badge {
    display: inline-flex;
    align-items: center;
    margin-top: 0.35rem;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    font-size: 0.8rem;
    font-weight: 600;
    line-height: 1.2;
}
.price-variance-badge.is-above {
    color: var(--bs-success-text-emphasis, #0f5132);
    background: var(--bs-success-bg-subtle, #d1e7dd);
}
.price-variance-badge.is-below {
    color: var(--bs-danger-text-emphasis, #842029);
    background: var(--bs-danger-bg-subtle, #f8d7da);
}

/* Body revealed by the "Add line items" button. Both instances of that button
   (display state and inside the editor) are plain Bootstrap
   .btn-outline-primary and need no rules here — deliberately solid-outlined
   buttons rather than link text, which was too easy to miss. */
.inline-price-breakdown-body {
    margin-top: 0.5rem;
}
