# 脱げ方の札(2026-08-07)— 衣装とは別に持ち、その場で混ぜる
#
# ■ なぜ作り直したか(ユーザー案)
#   これまでは衣装ごとに「めくる/ずらす」の英文を手書きしていた(_undress_types.yaml)。
#   そのため:
#     ・同じ段は毎回まったく同じ文 → 100枚のうち40枚が一字一句同じ衣装記述だった
#     ・**全裸になるのは余韻の6枚だけ**。山場でも上は着たまま(ユーザー実測)
#     ・衣装を足すたびに6段ぶんの英文を書く必要があった
#   ユーザー案「衣装に脱ぎ方を埋め込まず、別に用意してミックスする」に沿って作り直す。
#
# ■ Danbooru のタグ体系とぴったり合う
#   調べたら Danbooru は **衣類の呼び名 × 脱げ方** の2軸でタグを持っていた。
#     shirt + lift  → shirt_lift   (107,771枚)
#     shorts + pull → shorts_pull  (  9,973枚)
#     panties + aside → panties_aside (32,760枚)
#   → その場で組み立てられる。詳細と枚数は docs/research/46-danbooru-undress-tag-matrix.md
#
# ■ 大事な決まり
#   1) **実在しない組み合わせは作らない。** `shorts_lift` は163枚=事実上存在しない。
#      衣類ごとに「使える脱げ方」を持ち(pipeline/undress.py の GARMENTS)、無いものは選ばせない。
#   2) **段の順番は戻らない。** 各候補に level(露出の度合い)を持たせ、
#      前の段より小さい level は選ばない。前段で脱いだのに中核で着ている、を防ぐ。
#   3) 候補は段ごとに複数。1枚ごとに選び直すので、同じ段でも絵が変わる。
#
# ■ ★2026-08-11 追加: 下着(underwear)の欄（ユーザー報告）
#   症状: 「Tシャツをめくり上げたときの下着が毎回変わる。金色のビキニになったりする」
#   原因: **17ある候補すべてで、下着について一言も書いていなかった。**
#         衣装ファイルには `parts.underwear` があるのに、札がその欄を一度も読んでいない。
#         → 絵のAIから見ると「めくった下は空欄」なので、毎回好きなものを描いていた。
#   直し方: 各候補に underwear を足す。使う脱げ方は **"worn" と "off" だけ**にする。
#     ・"worn" は衣装ファイルの文字をそのまま出す(`{worn}`)ので、**色が保てる**
#     ・"lift"/"aside" は `{tag} lift` の形になるが、`bra and panties` のような
#       2つ書いた欄は tag が `panties` にしか当たらず `panties lift`(実在しない)が出る。
#       → 状態は extra に**実在タグ**で書き、脱げ方は worn/off に固定する。
#   ★下着の欄が空の衣装(水着など)は "worn" でも1文字も出ない。既存の出方は変わらない。
#   ★候補の絞り込み(candidates_for)は top/bottom しか見ないので、
#     下着を足しても候補が減ることはない。
#   実測(2026-08-11): panties 811,211 / bra 273,294 / white_panties 240,506 /
#     white_bra 45,400 / panty_pull 58,726 / panties_aside 32,849 /
#     panties_around_one_leg 27,034 / bra_strap 13,183 / bra_lift 12,815
#     ★存在しない語: bra_visible(0) / plain_bra(0) / bra_removed(0) → 使わない

version: 1

# ★★2026-08-16 追加: **段ごとの打ち消し**(全衣装・エディタで共通)。
#
# ■ なぜ要るか(制服ブレザーの実画像6枚で発覚)
#   導入は「きちんと着ている」段なのに、**ブレザーを着ておらず肩に掛けて手に持っていた**。
#   しかも接近のほうが着込んで見える = 順番が逆に見えた。
#   原因: 「きちんと着ている」と言う語が**1つも効いていなかった**。実測(2026-08-16):
#       fully_dressed 0 / fully_clothed 0 / dressed 0 / clothed 0 / neatly_dressed 0
#   手書き時代から全パックの導入に `fully dressed, neatly worn` と書いてあったが、
#   **どれも存在しないタグ**で、ずっと絵に効いていなかった。
#
# ■ どう直すか
#   「着ている」と言う語が無いなら、**「脱ぎかけ」を打ち消す**。実測(2026-08-16):
#       clothes_around_waist 22,787 / undressing 68,274 / partially_undressed 9,494
#   ★服の**形**を打ち消してはいけない(オフショルの服を選んだ人の衣装が壊れる)。
#     打ち消すのは「着方が崩れている状態」だけ。
#
# ★★2026-08-16(実画像で発覚・入れた直後に自分で踏んだ):
#   `jacket on shoulders`(33,498) を打ち消しに入れたら、
#   **制服の導入からブレザーが丸ごと消えた**(接近では着ている = この打ち消しがある段だけ消えた)。
#   打ち消したいのは「肩に掛けている着方」なのに、`jacket` という語がブレザー本体と
#   ぶつかって、服そのものを消してしまった。
#   → **服の名前を含む語は打ち消しに使わない。** 同じ理由で `bra` も使えない
#     (水着のビキニトップを消しかねない)。打ち消してよいのは服の名前を含まない語だけ。
#
# ■ 透け対策も1か所に置く
#   部屋着だけが「透けない」打ち消しを全段に持っていたが、実測すると
#   `see-through` 0 / `transparent clothes` 0 / `bra visible through shirt` 0 /
#   `clinging wet fabric` 0 = **効いていたのは `wet clothes` 61,187 だけ**だった。
#   制服にはそもそも無く、実画像で**ワイシャツが透けて白ブラが見えていた**。
#   実在する語は `see-through clothes` 215,455。
#   ★衣装自体がシアーを名乗っているときは外す(選んだ人の衣装を壊さないため。
#     判定は pipeline/recipe.py 側)。
#
# ■ ★★2026-08-19 追加: **乳を打ち消す語**(ユーザー実測「着衣のカットで最初から乳が出ている」)
#   それまでの導入・接近の打ち消しは「着崩れ」を消す語だけで、**乳を消す語が1語も無かった**。
#   一方 positive 側には胸の語が4つ(large breasts / inverted nipples / hanging breasts /
#   breasts apart / mole on breast)、服の語は実質2つ(t-shirt / shorts。`cotton` は実測0枚)
#   しか無く、綱引きとして最初から負けていた。
#   ★実測(2026-08-19・実在する語だけを使う):
#       nipples 1,127,171 / nude 684,555 / topless_female 88,155 / breasts_out 87,470
#       / areolae 17,683
#     ★`topless`(0枚) `exposed breasts`(0枚) は死語なので使わない。
#   ★`no bra` は**使わない**。この上の教訓どおり「服の名前を含む語は打ち消しに使わない」
#     (水着のビキニトップを消しかねない)。
#   ★足すのは intro / approach だけ。前戯以降に足すと**脱げなくなる**(商品の中身を殺す)。
stage_negative:
  intro: "clothes around waist, undressing, partially undressed,
    see-through clothes, wet clothes,
    nipples, areolae, nude, topless female, breasts out"
  approach: "see-through clothes, wet clothes,
    nipples, areolae, nude, topless female, breasts out"

# level = 露出の度合い(0:着衣 → 5:全裸)。段をまたいで戻らないための物差し。
stages:

  intro:
    - id: worn
      label_ja: きちんと着ている
      level: 0
      top:    {method: "worn"}
      bottom: {method: "worn"}

  approach:
    - id: loose
      label_ja: 着崩れ
      level: 1
      top:    {method: "worn", extra: "clothes pull"}
      bottom: {method: "worn"}
    - id: lift_slight
      label_ja: 裾が上がる
      level: 1
      top:    {method: "lift", extra: "midriff"}
      bottom: {method: "worn"}
      # ★★2026-08-16(実画像100枚で発覚・ユーザー指摘「白のブラジャーになっていない」):
      #   **この候補だけ下着を1文字も書いていなかった。**
      #   `midriff`(お腹)のつもりでも `shirt lift` は Danbooru では
      #   **胸まで持ち上げる絵**が多数派なので、実際にはブラが見える構図になる。
      #   書いていないとモデルが毎回決め直すので、**青いブラになったり、ブラ無しになったり**した
      #   (s13=青いレースのブラ / s07=ブラ無し。どちらも `white bra` と書いてあるのに)。
      #   → 「着ている」で色つきのまま出す。2026-08-11 に前戯以降だけ直して、
      #     接近の2候補を取りこぼしていた。
      underwear_top: {method: "worn"}
    - id: shoulder
      label_ja: 肩が出る
      level: 1
      top:    {method: "worn", extra: "off shoulder, bare shoulders"}
      bottom: {method: "worn"}
      # 肩が出ればブラひもが見える(bra_strap 13,190枚)
      # ★★2026-08-12 直した: 前は `extra: "bra strap"` と**手書きで固定**していた。
      #   下着がブラでない衣装にも出るので、和装で `white juban, bra strap` =
      #   **襦袢を着ているのにブラのひも**が出ていた(振袖の接近)。
      #   → 状態の言い方は服から引く("strap" は pipeline/undress.py の表で
      #     ブラだけに許可。実測 bra_strap 13,190 / juban_strap・camisole_strap 等は 0)。
      #   ブラ以外の下着では「着ているとだけ言う」に自動で落ちる。
      underwear_top: {method: "strap"}

  foreplay:
    # ★同上(前戯ぶん)。理由は中核側のコメントを見る。一体もの(レオタード・水着・ボディスーツ)専用**の候補。
    - id: onepiece_aside
      label_ja: 一体ものを横へずらす
      level: 2
      requires_top: [leotard, swimsuit, one-piece swimsuit, bodysuit]
      top:    {method: "aside", extra: "breasts out, nipples"}
    - id: onepiece_pull
      label_ja: 一体ものを引き下ろす
      level: 2
      requires_top: [leotard, swimsuit, one-piece swimsuit, bodysuit]
      top:    {method: "pull", extra: "breasts out, nipples"}

    - id: top_out
      label_ja: 上をめくって胸を出す
      level: 2
      top:    {method: "lift", extra: "breasts out, nipples"}
      bottom: {method: "worn"}
      # 胸を出す = ブラも一緒に上へ(bra_lift 12,815枚)。下はまだ穿いている
      underwear_top: {method: "lift_up"}
    - id: top_open
      label_ja: 上の前を開く
      level: 2
      top:    {method: "open", extra: "breasts out, nipples"}
      bottom: {method: "worn"}
      underwear_top: {method: "lift_up"}
    - id: top_off
      label_ja: 上を脱ぐ
      level: 3
      top:    {method: "off", extra: "topless female, nipples"}
      bottom: {method: "worn"}
      # 上半身は裸(topless female)なのでブラは書かない。下着はまだ穿いている
      underwear_top: {method: "off"}

  main:
    # ★2026-08-11 追加(段1・ニットの切り替えで気づいた): **スカート系のたくし上げ**。
    #   手書きのニットは中核が「スカートをたくし上げ」だったが、札には
    #   「引き下ろす(pull)」しか無く、**下が裸になる**方向にしか行けなかった。
    #   ロングスカート・プリーツスカートは「たくし上げて下着を横へずらす」が定番。
    #   実測: skirt_lift 93,576 / panties_aside 32,849(どちらも実在・十分に強い)
    #   ★短パン(shorts)は lift が使えない(実測163枚)ので、この候補は自動で外れる。
    #     = 部屋着の出方は1文字も変わらない。
    - id: bottom_lift
      label_ja: 下をたくし上げて下着をずらす
      level: 3
      top:    {method: "lift", extra: "breasts out, nipples"}
      bottom: {method: "lift"}
      underwear_top: {method: "lift_up"}
      underwear_bottom: {method: "aside"}
    # ★★2026-08-11 追加(段0): **一体もの(レオタード・水着・ボディスーツ)専用**の候補。
    #   実測で発覚: バニーガール衣装を札に切り替えると **中核の候補が0個**になり、
    #   衣装の指定が空になる。原因は2つ:
    #     ・レオタードは「めくる」「前を開く」が実在しない(使えるのは pull / aside だけ)
    #     ・下半身が網タイツで、これは脱げない付属品なので「引き下ろす」が成立しない
    #   → 上下が分かれていない服のための段を作る。**下半身の欄は指定しない**
    #     (一体ものに「下を脱ぐ」は無いため)。
    #   ★実在タグと枚数(2026-08-11 実測): leotard_aside 8,930 / leotard_pull 4,081 /
    #     swimsuit_aside 7,000 / one-piece_swimsuit 182,213 / bodysuit 179,957
    #   ★`requires_top` で**一体ものにだけ**使う。Tシャツ等は pull も使えるので、
    #     これを付けないと部屋着の出方まで変わってしまう(検証済みの衣装を勝手に動かさない)。
    - id: onepiece_aside
      label_ja: 一体ものを横へずらす
      level: 3
      requires_top: [leotard, swimsuit, one-piece swimsuit, bodysuit]
      top:    {method: "aside", extra: "breasts out, nipples"}
    - id: onepiece_pull
      label_ja: 一体ものを引き下ろす
      level: 3
      requires_top: [leotard, swimsuit, one-piece swimsuit, bodysuit]
      top:    {method: "pull", extra: "breasts out, nipples"}
    - id: bottom_down
      label_ja: 下を足首まで下ろす
      level: 3
      top:    {method: "lift", extra: "breasts out, nipples"}
      bottom: {method: "pull", extra: "bottomless"}
      # ★2026-08-11(ユーザー決定「中核でも絶頂でも混ざっているのが理想」)。
      #   下は裸(bottomless)なので**パンティは書かない**が、
      #   上は「ブラを上げて乳首が出ている」と明記する。
      #   書かないでいると 中核108枚が運任せになり、出たり出なかったりしていた。
      #   ブラごと外れている絵は topless female の候補が受け持つ = **狙って混ざる**。
      underwear_top: {method: "lift_up"}
    - id: bottom_aside
      label_ja: 下を横へずらす
      level: 3
      top:    {method: "lift", extra: "breasts out, nipples"}
      bottom: {method: "aside"}
      # ずらして下着が見える段。panties_aside 32,849枚
      underwear_top: {method: "lift_up"}
      underwear_bottom: {method: "aside"}
    # ★2026-08-07 追加(検査で発覚): 前開きの衣装(制服のシャツ・カーディガン・着物)は
    #   「めくる」が使えず、中核の候補が1つしか残らなかった=同じ絵が40枚並ぶ。
    #   `open shirt` は 148,733枚。前を開いたままが本来の描き方。
    - id: top_open_bottom_down
      label_ja: 上は前を開き、下は下ろす
      level: 3
      top:    {method: "open", extra: "breasts out, nipples"}
      bottom: {method: "pull", extra: "bottomless"}
      underwear_top: {method: "lift_up"}
    - id: top_off_bottom_down
      label_ja: 上は脱ぎ、下は下ろす
      level: 4
      top:    {method: "off", extra: "topless female, nipples"}
      bottom: {method: "pull", extra: "bottomless"}
      underwear_top: {method: "off"}
      underwear_bottom: {method: "off"}

  climax:
    - id: bunched
      label_ja: 上はまくれ上がり、下は脱げている
      level: 4
      top:    {method: "lift", extra: "breasts out, nipples"}
      bottom: {method: "off", extra: "bottomless"}
      # 脱ぎかけが片足に残る(panties_around_one_leg 27,034枚)。上はブラを上げた状態
      underwear_top: {method: "lift_up"}
      underwear_bottom: {method: "off", extra: "panties around one leg"}
    - id: top_off
      label_ja: 上も脱いでいる
      level: 4
      top:    {method: "off", extra: "topless female, nipples"}
      bottom: {method: "off", extra: "bottomless"}
      underwear_top: {method: "off"}
      underwear_bottom: {method: "off", extra: "panties around one leg"}
    # ★ユーザー指摘「全裸の絵が余韻の6枚だけ」への対応。山場でも全裸を選べるようにする。
    - id: nude
      label_ja: 全裸
      level: 5
      top:    {method: "off"}
      bottom: {method: "off"}
      underwear_top: {method: "off"}
      underwear_bottom: {method: "off"}
      whole:  "completely nude, nipples"

  afterglow:
    - id: nude_clothes_on_floor
      label_ja: 全裸・服は床に
      level: 5
      top:    {method: "off", extra: "on floor"}
      bottom: {method: "off", extra: "on floor"}
      underwear_top: {method: "off"}
      underwear_bottom: {method: "off"}
      whole:  "completely nude"
    - id: naked_shirt
      label_ja: 裸に上だけ羽織る
      level: 4
      # ★上がシャツ系の衣装でだけ使う。`naked shirt`(20,208枚)は「裸に上だけ羽織る」絵で、
      #   ビキニや着物に付けると絵と食い違う(2026-08-07 検査で発見)。
      # ★2026-08-11: naked_* の実在タグがある服だけ。カーディガン(389枚)とパーカーは外した。
      requires_top: [shirt, dress shirt, sweater, jacket, coat]
      top:    {method: "naked", extra: "open clothes"}
      bottom: {method: "off", extra: "bottomless"}
      underwear_top: {method: "off"}
      underwear_bottom: {method: "off"}
    - id: nude
      label_ja: 全裸
      level: 5
      top:    {method: "off"}
      bottom: {method: "off"}
      underwear_top: {method: "off"}
      underwear_bottom: {method: "off"}
      whole:  "completely nude"

# ★★★カードが名指ししたときだけ引ける棚(2026-08-22)。
#
# なぜ `stages:` に足さないか:
#   `stages:` に足すと**他のカードのサイコロに混ざる**。直したいのは
#   「男性の乳首を舐める/つまむ」の2枚だけなので、他のカードを1文字も変えない置き場が要る。
#   ここは `pipeline/undress.py` の `card_candidate()` からしか読まれない。
#
# 使い方: `scenes/cards.yaml` のカードに `female_undress: top_kept` と書く。
# ★実在しない組み合わせ(その衣装にその脱げ方が無い)なら**エラーで止まる**。
#   黙って別のものに差し替えない(カードに書いたのに効かない事故を防ぐ)。
by_card:
  # ★なぜ上を着せたままにするか(実測・2026-08-22):
  #   「女性が男性の乳首を舐める」正解の絵312枚のうち、女性が服から胸を出しているのは
  #   **17枚＝5.5%**しかない。いっぽう、うちの刷り出しは 10枚中10枚＝**100%**だった。
  #   画面の中で「乳首」と呼べるのが彼女の胸だけになり、彼の舌と手が全部そこへ行っていた
  #   (実画像26枚で確認。0/30 → 0/7 → 0/9)。
  #   ★同じ文の中で `clothed female nude male`(女は着衣・男は全裸)と
  #     `breasts out`(胸を出す)が**正面から矛盾**してもいた。
  # ★下は脱いだままにする。カードの `expected_zones: [genitals]` の申告と合う。
  # ★level 2 = 前戯と同じ度合い。段の並び(露出が戻らない見張り)を壊さない。
  # ★★下の脱ぎ方は **"off"** にすること(2026-08-22 に踏んだ穴)。
  #   最初 `pull` にしていたら、バニー衣装(下が網タイツ)で
  #   **`fishnets pull` は実在しない**ため候補ごと不成立になり、**生成が止まった**。
  #   `off` / `worn` / `naked` の3つだけが**衣類の種類に依らず成立する**
  #   (`pipeline/undress.py` の `_slots_ok`)。カード指定は全衣装で成立しないと使えない。
  top_kept:
    label_ja: 上は着たまま・下だけ脱ぐ
    level: 2
    top:    {method: "worn"}
    bottom: {method: "off", extra: "bottomless"}
    underwear_top: {method: "worn"}
    underwear_bottom: {method: "off"}

# 脱げ方 → Danbooru のタグの作り方。{tag} に衣類の呼び名が入る。
# ★"off" は必ずクォートすること。YAML は off/on/yes/no を**真偽値として読む**ため、
#   裸のまま書くと False になり、脱ぐ指定が丸ごと消える(2026-08-07 実測で発覚。
#   「上は脱ぎ」の候補から topless female が消えていた)。
methods:
  worn:   {label_ja: 着ている,     pattern: "{worn}"}
  lift:   {label_ja: めくり上げる,  pattern: "{tag} lift"}
  pull:   {label_ja: 引き下ろす,   pattern: "{tag} pull"}
  aside:  {label_ja: 横へずらす,   pattern: "{tag} aside"}
  # ★2026-08-11: 「着ている」が強すぎて勝ってしまうので、状態側に重みを付けた版。
  #   実測: bra 273,294枚 : bra_lift 12,815枚 = **21対1**。ただ並べると
  #   「ブラを着けたまま乳首が出ている」絵になる(2026-08-11 朝の実害)。
  lift_up: {label_ja: 上へずらす(強め), pattern: "({tag} lift:1.4)"}
  # ★2026-08-12: ひもが見える。**ブラだけ**実在する(bra_strap 13,190)。
  #   他の下着(襦袢・キャミ・水着)では表が許可しないので自動で出ない。
  strap:  {label_ja: ひもが見える,   pattern: "{tag} strap"}
  # ★2026-08-11: 「裸に上だけ羽織る」。服の種類に合った実在タグを使う({naked})。
  #   セーターに `naked shirt` を当てるとワイシャツに化けた(実物で確認)。
  naked:  {label_ja: 裸に羽織る,    pattern: "{naked}"}
  open:   {label_ja: 前を開く,     pattern: "open {tag}"}
  "off":  {label_ja: 脱ぐ,        pattern: ""}          # 何も書かない=無くなる
