/* The rich editor (ADR-0016 decision 6; core/_rich_editor.html, core/rich-editor.js),
   loaded with richtext.css by {% rich_editor_css %}.

   Nothing moves when the editor starts (CLS 0): under html.js the toolbar takes its room
   from the first paint (hidden until ready), and the editing box and the textarea it
   replaces are the same height (--rich-box, from the textarea's rows: .rich--rows-N).
   The box scrolls inside and can be made taller by its corner, like the textarea. Without
   JavaScript only the textarea shows; when the editor fails to load, the textarea stays
   and the toolbar's room goes. */

.rich{--rich-rows:8;--rich-box:max(180px,calc(var(--rich-rows) * 1.8em + 29px));display:grid;gap:6px;min-width:0}
/* Every whole number of rows the form side allows (richforms.ROWS_MIN to ROWS_MAX): a number
   without its class would size the box as 8 rows while the textarea it replaces keeps its own. */
.rich--rows-2{--rich-rows:2}
.rich--rows-3{--rich-rows:3}
.rich--rows-4{--rich-rows:4}
.rich--rows-5{--rich-rows:5}
.rich--rows-6{--rich-rows:6}
.rich--rows-7{--rich-rows:7}
.rich--rows-8{--rich-rows:8}
.rich--rows-9{--rich-rows:9}
.rich--rows-10{--rich-rows:10}
.rich--rows-11{--rich-rows:11}
.rich--rows-12{--rich-rows:12}
.rich--rows-13{--rich-rows:13}
.rich--rows-14{--rich-rows:14}
.rich--rows-15{--rich-rows:15}
.rich--rows-16{--rich-rows:16}
.rich--rows-17{--rich-rows:17}
.rich--rows-18{--rich-rows:18}
.rich--rows-19{--rich-rows:19}
.rich--rows-20{--rich-rows:20}
.rich--rows-21{--rich-rows:21}
.rich--rows-22{--rich-rows:22}
.rich--rows-23{--rich-rows:23}
.rich--rows-24{--rich-rows:24}
/* The body's textarea only (a dialog's description field keeps its own rows). */
.rich>textarea{block-size:var(--rich-box);line-height:1.8}

.rich__toolbar,.rich__surface{display:none}
.js .rich__toolbar{display:flex;visibility:hidden}
.js .rich[data-rich-state="ready"] .rich__toolbar{visibility:visible}
.js .rich[data-rich-state="ready"] .rich__surface{display:block}
.js .rich[data-rich-state="failed"] .rich__toolbar{display:none}
/* The no-JS "서식 없이 저장" box: only where the textarea is what is posted. */
.js .rich:not([data-rich-state="failed"]) .rich__fallback{display:none}
html:not(.js) .rich__keys,.rich[data-rich-state="failed"] .rich__keys{display:none}
/* The keyboard line is for screen readers (the body's aria-describedby) on every screen, never printed: nothing explains the obvious (user rule 2026-10-20). */
.rich__keys{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* Toolbar (APG toolbar; v0.7.1 icons, the user's sample of 2026-10-14): commands are icons
   (Lucide, the vendored sprite) named by aria-label and a tooltip; 문단 모양, 글꼴 and 글자
   크기 show their current value in words, like a select; the colour menus show a bar in the
   current colour. A pressed toggle is filled and framed (not colour alone), as is an open
   menu's button. */
.rich__toolbar{position:relative;flex-wrap:wrap;align-items:center;gap:2px;padding:6px;border:1px solid var(--line);border-radius:14px;background:var(--surface);-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
.rich__btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:2px;min-height:var(--target-min);min-width:var(--target-min);padding:4px 8px;border:1px solid transparent;border-radius:10px;background:transparent;color:var(--ink);font-family:var(--sans);font-size:.9rem;line-height:1.3;cursor:pointer}
.rich__btn--icon{padding-inline:6px}
.rich__btn:hover{background:var(--sunk)}
.rich__btn:focus-visible,.rich__toolbar--keys .rich__btn:focus{outline:3px solid var(--focus);outline-offset:1px}
.rich__btn[aria-pressed="true"]{border-color:var(--ink);background:var(--yellow-soft)}
.rich__btn[aria-pressed="true"] .rich__icon{stroke-width:2.5}
.rich__btn[aria-expanded="true"]{border-color:var(--line-strong);background:var(--sunk)}
.rich__btn[aria-disabled="true"]{color:var(--muted);cursor:default}
.rich__btn[aria-disabled="true"]:hover{background:transparent}
.rich__sep{align-self:stretch;width:1px;margin:6px 3px;background:var(--line)}
.rich__sep--wrapped{visibility:hidden} /* at a wrapped row's end or start (rich-editor.js) */
/* An icon: the sprite's symbol draws its own strokes in the text colour (currentColor). */
.rich__icon{flex:none;width:20px;height:20px;pointer-events:none}
.rich__caret{flex:none;width:14px;height:14px;margin-inline-start:1px;color:var(--ink-2);pointer-events:none}
/* A colour menu's face: its icon over a bar in the current colour (rich-editor.js copies the
   chosen sample's palette class onto the bar). The text colour's bar is that colour; the
   background colour's bar is that background, framed while there is none. */
.rich__glyph{display:inline-grid;justify-items:center;gap:1px}
.rich__bar{display:block;width:18px;height:4px;border-radius:1px}
.rich__bar--color{background-color:currentColor}
.rich__bar--highlight{box-shadow:inset 0 0 0 1px var(--line-strong)}
.rich__glyph .rich__icon{width:18px;height:18px}
/* A select-like menu's face: the current item's name, as wide as the longest one (the
   names stacked unseen in the same cell keep the width: nothing moves as it changes). */
.rich__btn--value{justify-content:space-between;gap:4px;padding-inline:10px 6px}
.rich__value{display:grid;text-align:start}
.rich__value>*,.rich__ghost>*{grid-area:1/1}
.rich__ghost{display:grid;visibility:hidden}
.rich__now{white-space:nowrap}
.rich__ghost>*{white-space:nowrap}

/* Tooltips (role="tooltip"; never a title, which the keyboard cannot show): a control's
   name and shortcut, below it (above it on a wrapped toolbar's first rows: rich-editor.js
   .rich__tip--above, so it never covers another control). Hover shows one after a short
   wait (pointers that hover), keyboard focus at once, a long touch from rich-editor.js
   (.rich__btn--tip); Esc or a click on it hides it (.rich__toolbar--quiet); an open menu's
   button shows none. It stays while the pointer is over it (it is part of its control). */
.rich__tip{position:absolute;z-index:25;top:calc(100% + 6px);left:50%;transform:translateX(-50%);visibility:hidden;width:max-content;max-width:16em;padding:5px 9px;border-radius:8px;background:var(--ink);color:var(--surface);font-family:var(--sans);font-size:.8125rem;font-weight:400;line-height:1.4;white-space:nowrap;text-align:center;pointer-events:auto;transition:visibility 0s}
.rich__tip kbd{margin-inline-start:6px;font:inherit;color:var(--on-deep-2)}
.rich__tip--start{left:0;transform:none}
.rich__tip--end{left:auto;right:0;transform:none}
.rich__tip--above{top:auto;bottom:calc(100% + 6px)} /* not the last row: never over a control */
@media (hover:hover){
  .rich__btn:hover>.rich__tip{visibility:visible;transition-delay:.45s}
}
.rich__btn:focus-visible>.rich__tip,.rich__toolbar--keys .rich__btn:focus>.rich__tip,.rich__btn--tip>.rich__tip{visibility:visible;transition-delay:0s}
.rich__btn[aria-expanded="true"]>.rich__tip,.rich__toolbar--quiet .rich__btn>.rich__tip{visibility:hidden;transition-delay:0s}

/* Menus (APG menu button): under their button; on a phone, across the toolbar. */
.rich__menu{position:relative;display:inline-flex}
.rich__list{position:absolute;z-index:30;top:calc(100% + 4px);inset-inline-start:0;width:max-content;min-width:11em;max-width:min(22em,calc(100vw - 32px));margin:0;padding:6px;list-style:none;border:1px solid var(--line-strong);border-radius:12px;background:var(--surface);box-shadow:var(--shadow)}
.rich__list[hidden]{display:none}
.rich__list--end{inset-inline:auto 0} /* would pass the window's right edge (rich-editor.js) */
.rich__item{display:flex;align-items:center;gap:10px;width:100%;min-height:var(--target-min);padding:4px 10px;border:0;border-radius:8px;background:transparent;color:var(--ink);font-family:var(--sans);font-size:.92rem;text-align:start;cursor:pointer}
.rich__item:hover{background:var(--sunk)}
.rich__item:focus-visible,.rich__toolbar--keys .rich__item:focus{outline:3px solid var(--focus);outline-offset:-3px;background:var(--sunk)}
.rich__item[aria-disabled="true"]{color:var(--muted);cursor:default}
/* The chosen item: a filled dot (shape, not colour alone). */
.rich__item[role="menuitemradio"]::before{content:"";flex:none;width:10px;height:10px;border:1.5px solid currentColor;border-radius:50%}
.rich__item[aria-checked="true"]::before{background:currentColor}
.rich__item[aria-checked="true"]{font-weight:700}
/* Each item shows itself: a typeface or size in that face or size, a heading as a heading. */
.rich__preview--read{font-family:var(--read)}
.rich__preview--h2,.rich__preview--h3{font-family:var(--serif);font-weight:700;line-height:1.3}
.rich__preview--h2{font-size:1.25rem}
.rich__preview--h3{font-size:1.08rem}
/* A colour's sample: "가" in that colour, or on that background (:where: the palette class
   gives the background); 없음 is crossed out. */
.rich__swatch{display:inline-grid;place-items:center;flex:none;width:1.9em;height:1.9em;border:1px solid var(--line-strong);border-radius:6px;font-family:var(--read);font-weight:700;line-height:1}
:where(.rich__swatch){background-color:var(--surface)}
.rich__swatch--highlight:not([class*=" rt-h-"]){background-image:linear-gradient(to top right,transparent calc(50% - 1px),var(--danger) calc(50% - 1px) calc(50% + 1px),transparent calc(50% + 1px))}
/* The colour menus: a grid of named samples. The chosen one is framed and its name bold. */
.rich__list--grid{display:grid;grid-template-columns:repeat(3,minmax(5em,1fr));gap:2px;min-width:0}
.rich__list--grid>li{display:flex}
.rich__list--grid .rich__item{flex-direction:column;justify-content:center;gap:4px;padding:6px 4px;font-size:.85rem;text-align:center}
.rich__list--grid .rich__item::before{content:none}
.rich__list--grid .rich__item[aria-checked="true"] .rich__swatch{outline:2px solid var(--ink);outline-offset:2px}
@media (max-width:600px){
  .rich__menu{position:static}
  .rich__list{inset-inline:6px;width:auto;max-width:none}
  .rich__list--grid{grid-template-columns:repeat(4,minmax(0,1fr))}
  /* Tooltips hang from the editor too, under the toolbar's one row, in its middle. */
  .rich__btn{position:static}
  .rich__tip,.rich__tip--start,.rich__tip--end,.rich__tip--above{top:62px;bottom:auto;left:0;right:0;margin-inline:auto;transform:none;font-size:.875rem}
  /* Phones (ADR-0017 decision 13): the tools on one row that scrolls sideways, as phone
     editors do, instead of five or six wrapped rows pushing the text box off the screen
     (and out of sight once the keyboard is up). A shadow at an edge says more tools lie
     that way (background-attachment: the covers move with the content, the shadows stay).
     The menus hang from the editor (position:relative below), not from the scrolling row,
     so the row never clips them; 62px is the one row's height (44px tools, 6px padding,
     1px border, and a 4px gap). */
  .rich{position:relative}
  .rich__toolbar{position:static;flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-inline:contain;scrollbar-width:thin;
    background:linear-gradient(to right,var(--surface) 30%,transparent) left/24px 100% no-repeat local,
      linear-gradient(to left,var(--surface) 30%,transparent) right/24px 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%,color-mix(in srgb,var(--ink) 22%,transparent),transparent) left/10px 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%,color-mix(in srgb,var(--ink) 22%,transparent),transparent) right/10px 100% no-repeat scroll,
      var(--surface)}
  .rich__toolbar>*{flex:none}
  .rich__list{top:62px}
}

/* The editing box: the textarea's box, scrolling inside. */
.rich__doc{display:block;block-size:var(--rich-box);overflow-y:auto;resize:vertical;padding:13px 16px;border:1.5px solid var(--line-strong);border-radius:14px;background:var(--surface);color:var(--ink);line-height:1.8}
.rich__doc:focus-visible{border-color:var(--ink);outline:3px solid var(--focus);outline-offset:2px;box-shadow:0 0 0 2px var(--bg)}
.rich__doc[aria-invalid="true"]{border-color:var(--ink);border-width:2px}
.rich__doc img{max-width:100%;height:auto;border-radius:8px}
.rich__doc .ProseMirror-selectednode{outline:3px solid var(--focus);outline-offset:2px}
.rich__doc table{white-space:normal}
.rich__doc .selectedCell{background:var(--yellow-soft)}

/* Photos and videos in the text (ADR-0016 v0.7.8; core/rich-figures.js). A figure shows as it
   will on the page (richtext.css gives its size and placement from the same classes) and is
   a block that is dragged: by its handle (a grip in its corner, always there on a touch
   screen), or whole with the mouse. The bar under the selected one is placed by these rules
   alone, never by a measured position (no style is written: the CSP), and the line where a
   dragged block will land is a widget between the blocks. */
/* No text of a figure is selected by a press (its note, its caption): a press selects the figure. */
.rich__fig{position:relative;cursor:grab;-webkit-user-select:none;user-select:none}
.rich__fig img{display:block;max-width:100%;height:auto;margin-inline:auto;border-radius:12px;background:var(--sunk)}
.rich__fig[class*="rt-fig-w"] img{width:100%}
.rich__fig--pending{min-height:120px;border:2px dashed var(--line-strong);border-radius:12px;background:var(--sunk)}
.rich__fig--pending img:not([src]){display:none}
.rich__fig--lifted{opacity:.45}
.rich__doc--moving,.rich__doc--moving *{cursor:grabbing}
/* The bar steps aside while a block is dragged: what is under it is where it may land. */
.rich__doc--moving .rich__figbar{visibility:hidden;pointer-events:none}
.rich__grip{position:absolute;z-index:3;top:6px;inset-inline-start:6px;display:grid;place-items:center;width:var(--target-min);height:var(--target-min);border:1px solid var(--line-strong);border-radius:10px;background:var(--surface);color:var(--ink);cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none;opacity:0}
.rich__fig:hover>.rich__grip,.rich__fig.ProseMirror-selectednode>.rich__grip{opacity:1}
@media (hover:none){.rich__grip{opacity:1}}
/* What a figure still lacks, said in words: uploading, refused, or no description. */
.rich__note{pointer-events:none;position:absolute;inset-inline:0;bottom:0;padding:6px 10px;border-top:1px solid var(--line-strong);border-radius:0 0 12px 12px;background:var(--yellow-soft);color:var(--ink);font-family:var(--sans);font-size:.85rem;line-height:1.4;white-space:normal}
.rich__note[hidden],.rich__caption[hidden]{display:none}
.rich__video{display:grid;place-items:center;aspect-ratio:16/9;padding:12px 14px;border:1.5px dashed var(--line-strong);border-radius:12px;background:var(--sunk);font-family:var(--sans);text-align:center;white-space:normal}

/* The bar of the selected figure: its choices as words (a size, a placement, the order,
   the description). On a screen wide enough it hangs under the figure, centred under a
   centred one and at the edge of a wrapped one, no wider than the box; the editor scrolls
   it into view (rich-figures.js). On a phone it is a sheet at the foot of the screen, where
   a thumb reaches, so a small box or a tall photo never hides it, and the figure keeps
   clear of it (scroll-margin). Nothing here is measured: no style is written (the CSP). */
.rich__figbar{position:absolute;z-index:20;top:calc(100% + 8px);left:50%;transform:translateX(-50%);display:flex;flex-wrap:wrap;gap:4px 14px;width:max-content;max-width:min(46rem,calc(100vw - 96px));padding:6px 10px;border:1px solid var(--line-strong);border-radius:14px;background:var(--surface);box-shadow:0 8px 24px var(--shadow);color:var(--ink);font-family:var(--sans);font-size:.9rem;line-height:1.3;text-align:start;white-space:normal;cursor:default}
.rich__fig.rt-fig-left>.rich__figbar{left:0;transform:none}
.rich__fig.rt-fig-right>.rich__figbar{left:auto;right:0;transform:none}
.rich__figgroup{display:flex;flex-wrap:wrap;align-items:center;gap:4px}
.rich__figgroup[hidden],.rich__figbtn[hidden]{display:none}
.rich__figlabel{margin-inline-end:2px;color:var(--ink-2);font-size:.8rem}
.rich__figbtn{display:inline-flex;align-items:center;gap:4px;min-height:var(--target-min);min-width:var(--target-min);padding:4px 10px;border:1px solid var(--line-strong);border-radius:10px;background:var(--surface);color:var(--ink);font:inherit;cursor:pointer}
.rich__figbtn:hover{background:var(--sunk)}
.rich__figbtn:focus-visible{outline:3px solid var(--focus);outline-offset:1px}
.rich__figbtn[aria-pressed="true"]{border-color:var(--ink);background:var(--yellow-soft);font-weight:700}
.rich__figbtn .rich__icon{width:18px;height:18px}
@media (max-width:600px){
  .rich__fig.ProseMirror-selectednode{scroll-margin-bottom:22rem}
  .rich__figbar,.rich__fig.rt-fig-left>.rich__figbar,.rich__fig.rt-fig-right>.rich__figbar{position:fixed;inset:auto 8px calc(var(--savebar-h,0px) + 12px);left:8px;right:8px;top:auto;transform:none;width:auto;max-width:none;max-height:min(20rem,50vh);overflow-y:auto;gap:2px 10px;padding:6px 8px}
  .rich__figbtn{padding-inline:8px;font-size:.85rem}
}
/* The five sizes (매우 작게 to 가득, 2026-10-20) are one row of 44px targets down to a 320px
   screen: there the groups' captions give way (the buttons' words and the groups' names are
   what a screen reader hears; the captions are only drawn). */
@media (max-width:360px){
  .rich__figlabel{display:none}
}
/* A very small figure that has a word to say (uploading, refused, no description) is as wide
   as the words need: in a column of a few letters the note would run up over the text above.
   What is saved is not wider (richtext.css has no such rule). */
.rich__fig.rt-fig-w20:has(>.rich__note:not([hidden])){min-width:min(100%,9rem)}
/* Where a dragged block will land: a line between the blocks that takes no room (the widget
   is as high as nothing), and the dropcursor's own for a figure dragged whole. */
.rich__dropline{position:relative;height:0;margin:0!important;pointer-events:none}
.rich__dropline::before{content:"";position:absolute;inset-inline:0;top:.55em;height:4px;margin-top:-2px;border-radius:2px;background:var(--focus)}
.rich__dropcursor{border-radius:2px;background:var(--focus);pointer-events:none}

/* What @tiptap/core 3.31.4 would write into a <style> element (src/style.ts, MIT; the
   editor runs with injectCSS: false, so these rules live here). The gap cursor's line is
   currentColor instead of black, and it does not blink when motion is reduced. */
.ProseMirror{position:relative}
.ProseMirror{word-wrap:break-word;white-space:pre-wrap;white-space:break-spaces;-webkit-font-variant-ligatures:none;font-variant-ligatures:none;font-feature-settings:"liga" 0}
.ProseMirror [contenteditable="false"]{white-space:normal}
.ProseMirror [contenteditable="false"] [contenteditable="true"]{white-space:pre-wrap}
.ProseMirror pre{white-space:pre-wrap}
img.ProseMirror-separator{display:inline!important;border:none!important;margin:0!important;width:0!important;height:0!important}
.ProseMirror-gapcursor{display:none;pointer-events:none;position:absolute;margin:0}
.ProseMirror-gapcursor:after{content:"";display:block;position:absolute;top:-2px;width:20px;border-top:1px solid currentColor;animation:ProseMirror-cursor-blink 1.1s steps(2,start) infinite}
@keyframes ProseMirror-cursor-blink{to{visibility:hidden}}
.ProseMirror-hideselection *::selection{background:transparent}
.ProseMirror-hideselection *::-moz-selection{background:transparent}
.ProseMirror-hideselection *{caret-color:transparent}
.ProseMirror-focused .ProseMirror-gapcursor{display:block}
@media (prefers-reduced-motion:reduce){.ProseMirror-gapcursor:after{animation:none}}
[data-motion="off"] .ProseMirror-gapcursor:after{animation:none}

/* Dialogs (APG modal dialog) */
.rich-dialog{width:min(36em,calc(100vw - 32px));max-height:calc(100vh - 32px);overflow:auto;padding:20px;border:1px solid var(--line-strong);border-radius:16px;background:var(--surface);color:var(--ink)}
.rich-dialog::backdrop{background:rgb(0 0 0 / .45)}
.rich-dialog__title{margin:0 0 8px;font-size:1.25rem;line-height:1.4}
.rich-dialog .field{margin-top:12px}
.rich-dialog__preview{margin:12px 0 0}
.rich-dialog__preview img{display:block;max-width:100%;max-height:240px;height:auto;border-radius:12px;background:var(--sunk)}
/* The description is a few lines (its rows), not a body's 180px floor. On a short screen
   the dialog scrolls inside and its actions stay at its foot, so 사진 넣기 is always in
   sight (bottom -20px: over the dialog's own padding). */
.rich-dialog textarea{min-height:0}
.rich-dialog__acts{position:sticky;bottom:-20px;z-index:1;display:flex;flex-wrap:wrap;gap:8px;margin:16px -20px -20px;padding:12px 20px 20px;background:var(--surface)}
.rich-dialog [aria-disabled="true"]{cursor:default}

@media (forced-colors:active){
  .rich__toolbar,.rich__list,.rich__doc,.rich-dialog{border-color:CanvasText}
  .rich__btn[aria-pressed="true"],.rich__btn[aria-expanded="true"]{border-color:Highlight}
  .rich__btn:focus-visible,.rich__item:focus-visible,.rich__doc:focus-visible{outline-color:Highlight}
  .rich__sep{background:CanvasText}
  .rich__tip{border:1px solid CanvasText}
  .rich__list--grid .rich__item[aria-checked="true"] .rich__swatch{outline-color:Highlight}
  .rich__bar{forced-color-adjust:none} /* the colour it names, as the sample shows it */
  .rich__figbar,.rich__grip,.rich__figbtn{border-color:CanvasText}
  .rich__figbtn[aria-pressed="true"]{border-color:Highlight}
  .rich__figbtn:focus-visible{outline-color:Highlight}
  .rich__dropline::before,.rich__dropcursor{background:Highlight}
  .rich__fig--pending,.rich__video{border-color:CanvasText}
}
