/*
 * BlazorQuill — Medium-style skin for Quill 2.x.
 *
 * Loaded as a plain stylesheet (not scoped CSS) on purpose: it has to out-cascade
 * quill.bubble.css / quill.snow.css, and consumers need to be able to override it
 * without fighting generated [b-xxxxx] scope attributes. Link it AFTER the Quill
 * theme stylesheets.
 *
 * Everything is namespaced under .bq-root so the page's other Quill instances
 * (if any) are untouched.
 */

.bq-root {
    position: relative;
    --bq-min-height: 60vh;
    --bq-max-width: 680px;
    --bq-insert-size: 32px;
    --bq-insert-gutter: 46px;
    --bq-insert-gap: 10px;
    --bq-ink: rgba(0, 0, 0, .84);
    --bq-ink-muted: rgba(0, 0, 0, .54);
    --bq-ink-faint: rgba(0, 0, 0, .35);
    --bq-spoiler-tint: var(--spoiler-surface, rgba(0, 0, 0, .06));
    --bq-spoiler-edge: var(--spoiler-border, rgba(0, 0, 0, .18));
    
    --bq-quote-bar: rgba(0, 0, 0, .84);
    --bq-quote-tint: rgba(0, 0, 0, .04);
    
    --bq-quote-ink: var(--bq-ink);
    --bq-serif: Charter, "Iowan Old Style", "Source Serif 4", "Source Serif Pro", Georgia, Cambria, "Times New Roman", Times, serif;
    --bq-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* ---------------------------------------------------------------- reset */
/* Quill's themes draw a 1px box and set their own font stack; strip both. */
.bq-root .ql-container,
.bq-root .ql-container.ql-bubble,
.bq-root .ql-container.ql-snow {
    border: none;
    font-family: inherit;
    font-size: inherit;
}

.bq-root .ql-editor {
    position: relative;
    padding: 0;
    min-height: var(--bq-min-height);
    outline: none;
    overflow-y: visible;
}

/* Snow's toolbar keeps a bottom rule but loses the box. */
.bq-root .ql-toolbar.ql-snow {
    border: none;
    border-bottom: 1px solid rgba(0, 0, 0, .08);
    padding: 8px 0 12px;
    margin-bottom: 24px;
    font-family: var(--bq-sans);
}

/* ------------------------------------------------------------ writing column */
/* Layout only. Typography — the type scale, headings, quotes, code, lists, rules,
   images and the spoiler card itself — lives in article-prose.css, under the
   .xc-prose class this editor puts on .ql-editor via its EditorClass parameter.
   That is the same class the reading surfaces carry, which is what stops the two
   from drifting apart. Nothing here may set a font, a colour or a margin that
   .xc-prose also sets. */
.bq-root.bq-medium .ql-editor {
    max-width: var(--bq-max-width);
    margin: 0 auto;
    caret-color: var(--bq-ink);
}

/* --------------------------------------------------------- placeholder */
/* Quill's default is italic and inset by the 15px padding we just removed. */
.bq-root .ql-editor.ql-blank::before {
    left: 0;
    right: 0;
    padding-inline: inherit;
    font-style: normal;
    color: var(--bq-ink-faint);
}

.bq-root.bq-medium .ql-editor.ql-blank::before {
    font-family: var(--bq-serif);
    font-size: 21px;
    line-height: 1.58;
}

/* Keep the placeholder aligned with the centred column. */
.bq-root.bq-medium .ql-container {
    display: block;
}

/* ------------------------------------------------- bubble tooltip (Medium black) */
.bq-root .ql-bubble .ql-tooltip {
    background-color: #000;
    border-radius: 4px;
    box-shadow: 0 1px 8px rgba(0, 0, 0, .25);
}

.bq-root .ql-bubble .ql-tooltip-arrow {
    border-bottom-color: #000;
}

.bq-root .ql-bubble .ql-tooltip.ql-flip .ql-tooltip-arrow {
    border-top-color: #000;
}

.bq-root .ql-bubble .ql-toolbar .ql-formats {
    margin: 6px 8px;
}

.bq-root .ql-bubble .ql-editor a {
    text-decoration: underline;
}

/* ------------------------------------------------- insert (+) control */
/* Absolutely positioned inside .ql-container, which Quill core already makes relative.
   JS writes left/top on the wrapper and nothing else, so everything visual lives here.
   The wrapper's left edge is the "+"; the option row grows to its right, over the empty
   line, the way Medium's does. */
.bq-root .bq-insert-wrap {
    position: absolute;
    top: 0;
    left: 0;
    transform: translateY(-50%);
    z-index: 2;
    display: flex;
    align-items: center;
    gap: var(--bq-insert-gap);
}

/* display:flex above would otherwise out-specify the UA sheet's [hidden] { display: none }. */
.bq-root .bq-insert-wrap[hidden] {
    display: none;
}

.bq-root .bq-insert,
.bq-root .bq-insert-option {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    box-sizing: border-box;
    width: var(--bq-insert-size);
    height: var(--bq-insert-size);
    margin: 0;
    padding: 0;
    appearance: none;
    -webkit-appearance: none;
    border: 1px solid var(--bq-ink-faint);
    border-radius: 50%;
    background: transparent;
    color: var(--bq-ink-muted);
    cursor: pointer;
    transition: color .12s ease, border-color .12s ease;
}

.bq-root .bq-insert:hover,
.bq-root .bq-insert-option:hover {
    border-color: var(--bq-ink);
    color: var(--bq-ink);
}

.bq-root .bq-insert:focus-visible,
.bq-root .bq-insert-option:focus-visible {
    border-color: var(--bq-ink);
    color: var(--bq-ink);
    outline: 2px solid var(--bq-ink);
    outline-offset: 2px;
}

.bq-root .bq-insert svg,
.bq-root .bq-insert-option svg {
    display: block;
    width: 60%;
    height: 60%;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.25;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* The options are hidden until the "+" is clicked; opening turns it into a close button.
   Rotating the glyph rather than the button keeps the focus ring square. */
.bq-root .bq-insert svg {
    transition: transform .15s ease;
}

.bq-root .bq-insert-wrap.bq-open .bq-insert {
    border-color: var(--bq-ink);
    color: var(--bq-ink);
}

.bq-root .bq-insert-wrap.bq-open .bq-insert svg {
    transform: rotate(45deg);
}

.bq-root .bq-insert-menu {
    display: none;
    align-items: center;
    gap: var(--bq-insert-gap);
}

.bq-root .bq-insert-wrap.bq-open .bq-insert-menu {
    display: flex;
}

/* Belt and braces: the JS gate already hides it whenever Quill is disabled. */
.bq-root.bq-readonly .bq-insert-wrap {
    display: none;
}

/* Both cases put a control where the blank-document placeholder would run underneath it:
   an open option row always, and a viewport too narrow for the gutter. */
.bq-root .ql-container.bq-insert-inset .ql-editor.ql-blank::before,
.bq-root .ql-container.bq-insert-open .ql-editor.ql-blank::before {
    visibility: hidden;
}

/* The editor deliberately keeps focus while the options are open (that is how the caret index
   survives the click), but a caret blinking beside them reads as two places to act at once. */
.bq-root .ql-container.bq-insert-open .ql-editor {
    caret-color: transparent;
}

/* ------------------------------------------------- @mention / #hashtag dropdown */
/* Rendered by Blazor as a child of .bq-root, which is the positioning context. The module
   reports caret bounds already translated into this element's space, and writes nothing
   itself — left/top arrive as an inline style and everything else lives here. */
.bq-root .bq-mention {
    position: absolute;
    z-index: 3;
    min-width: 220px;
    max-width: 320px;
    max-height: 264px;
    overflow-y: auto;
    padding: 4px;
    border: 1px solid rgba(0, 0, 0, .08);
    border-radius: 6px;
    background: #fff;
    box-shadow: 0 2px 12px rgba(0, 0, 0, .12);
    font-family: var(--bq-sans);
    font-size: 14px;
    line-height: 1.3;
    /* Nudged clear of the caret line so the panel never sits on the text it completes. */
    margin-top: 4px;
}

.bq-root .bq-mention-status {
    padding: 8px 10px;
    color: var(--bq-ink-muted);
}

.bq-root .bq-mention-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-radius: 4px;
    cursor: pointer;
    color: var(--bq-ink);
}

.bq-root .bq-mention-item:hover,
.bq-root .bq-mention-item-active {
    background: rgba(0, 0, 0, .06);
}

.bq-root .bq-mention-avatar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    overflow: hidden;
    background: rgba(0, 0, 0, .08);
    color: var(--bq-ink-muted);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
}

.bq-root .bq-mention-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.bq-root .bq-mention-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* Both lines truncate rather than wrap: a row has to stay one row, or the keyboard
   highlight jumps by an unpredictable amount. */
.bq-root .bq-mention-label,
.bq-root .bq-mention-secondary {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bq-root .bq-mention-secondary {
    color: var(--bq-ink-muted);
    font-size: 12px;
}

/* --------------------------------------------------------------- states */
.bq-root.bq-readonly .ql-editor {
    caret-color: transparent;
}

@media (max-width: 740px) {
    .bq-root {
        --bq-insert-size: 28px;
        --bq-insert-gutter: 38px;
        --bq-insert-gap: 8px;
    }

    /* Padding only — the narrow-screen type scale is article-prose.css's business,
       and setting a font-size here would override it on the editor alone. */
    .bq-root.bq-medium .ql-editor {
        padding: 0 4vw;
    }
}

/* ------------------------------------------------------ inline upload placeholder */
/* The skeleton IS the image: the placeholder shows the local file at its own intrinsic
   size, so the box it occupies is already the box the stored image will occupy and the
   swap costs no reflow. The shimmer and the progress bar are absolutely positioned
   inside that box, so neither contributes any layout of its own. */
/* Matches the margin and radius .xc-prose gives a real image, so the swap moves nothing. */
.bq-root .ql-editor .bq-upload {
    position: relative;
    display: block;
    margin: 2rem auto;
    max-width: 100%;
    line-height: 0;
    border-radius: 10px;
    overflow: hidden;
    /* Quill selects an embed by outlining it; without this the placeholder looks selected. */
    user-select: none;
}

/* The margin and radius belong to the wrapper, not to the preview inside it — .xc-prose img
   would otherwise apply both here as well, insetting the image from the shimmer that is
   positioned against the wrapper's own box. */
.bq-root .ql-editor .bq-upload-img {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 0;
    border-radius: 0;
    /* Reads as provisional without hiding what was picked. */
    opacity: .55;
    filter: blur(1.5px);
    transform: scale(1.01); /* hides the blur bleeding in from the edges */
}

.bq-upload-shimmer {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(100deg,
        transparent 20%, rgba(255, 255, 255, .55) 50%, transparent 80%);
    background-size: 220% 100%;
    animation: bq-shimmer 1.35s linear infinite;
}

@keyframes bq-shimmer {
    from { background-position: 120% 0; }
    to   { background-position: -120% 0; }
}

.bq-upload-bar {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    height: 3px;
    background: currentColor;
    opacity: .75;
    transform: scaleX(var(--bq-upload-progress, 0));
    transform-origin: 0 50%;
    transition: transform .15s linear;
}

.bq-upload-retry {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    translate: -50% -50%;
    display: none;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, .72);
    color: #fff;
    cursor: pointer;
    line-height: 0;
}

.bq-upload-retry svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.bq-upload-retry:hover { background: rgba(0, 0, 0, .85); }
.bq-upload-retry:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* Failure: stop the motion, tint the frame, and offer the way out. */
.bq-upload[data-bq-upload-state="error"] .bq-upload-shimmer {
    animation: none;
    background: rgba(190, 30, 30, .18);
}

.bq-upload[data-bq-upload-state="error"] .bq-upload-bar { display: none; }
.bq-upload[data-bq-upload-state="error"] .bq-upload-retry { display: inline-flex; }

@media (prefers-reduced-motion: reduce) {
    .bq-upload-shimmer {
        animation: none;
        background: rgba(0, 0, 0, .10);
    }

    .bq-upload-bar { transition: none; }
}

/* ------------------------------------------------------------ figures */
/* A picture and its caption, while they are being written. The reading surface styles
   these too (see article-prose.css) — what belongs HERE is only what the editor needs
   and a reader must never see: the prompt inside a caption nobody has written yet. */

.bq-root .ql-editor figure {
    margin: 2rem 0;
}

.bq-root .ql-editor figure img {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 0 auto;
    border-radius: 10px;
}

.bq-root .ql-editor figcaption {
    margin-top: .6rem;
    font-size: .875rem;
    line-height: 1.5;
    text-align: center;
    opacity: .75;
}

/* The prompt. Content comes from --bq-caption-placeholder, published onto the editor
   element by modules/figure.js from the host's localized string, so no placeholder text
   exists as markup and none of it can end up in the saved body.

   :empty is deliberately narrow — it stops matching the moment there is a character to
   read, including the <br> Quill leaves in a blank line, which is why the :has() rule
   below covers that case too. */
.bq-root .ql-editor figcaption:empty::before,
.bq-root .ql-editor figcaption:has(> br:only-child)::before {
    content: var(--bq-caption-placeholder, "");
    opacity: .55;
    pointer-events: none;
}
