/* 手機版（螢幕寬度小於 900px 時套用） */
@media (max-width: 900px){
  .app{
    flex-direction: column;   /* 左右並排 → 改成上下堆疊 */
  }
  .app .sidebar{
    width: 100%;              /* 側邊欄改成滿版寬。用 .app .sidebar 提高優先度，
                                  避免被後面桌面版的 .sidebar{width:340px} 蓋掉（兩者選擇器優先度原本相同，
                                  桌面版寫在後面會贏，導致手機版側邊欄一直卡在340px寬，右側留白） */
    max-height: 50vh;         /* 避免介紹文字太長把畫布擠到很下面 */
    overflow-y: auto;
  }
  .canvas-area{
    padding: 15px;
  }
  .toolbar-row{
    justify-content: center;  /* 按鈕置中，避免擠成一團 */
  }
  /* 任務25：這行「目前選擇：...」桌面版才顯示，手機版已經在收合pill上顯示同樣資訊，不用重複一份。
     用複合選擇器.toolbar-row.desktop-price-row提高優先度，避免被後面桌面版.toolbar-row{display:flex}蓋掉
     （兩者原本優先度相同，後寫的桌面版規則會贏，這裡踩到跟.tabs-wrap同樣的坑） */
  .toolbar-row.desktop-price-row{ display:none; }
  /* 任務25：手機版尺寸/方向選單收合成pill+下拉（或首次進入時的置中彈窗），
     這裡的.size-orientation-group（也就是#sizePanel）在手機版變成下拉/彈窗內容本身，
     不再是常駐展開的樣式；桌面版維持原本flex展開排列（見桌面版對應規則）。 */
  /* 這幾條都用 .size-pill-wrap 前綴提高優先度，避免被後面桌面版同名class的隱藏規則蓋掉
     （跟.tabs-wrap .tabs-toggle是同一種寫法，同一個原因） */
  .size-pill-wrap{ position:relative;margin-bottom:12px; }
  .size-pill-wrap .size-pill-toggle{
    display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;
    background:var(--color-dark-base);color:var(--color-light-text);border:none;
    border-radius:20px;padding:11px 16px;font-size:13.5px;font-weight:700;cursor:pointer;
  }
  .size-pill-wrap .size-pill-toggle .chev{
    color:var(--color-interactive);font-size:11px;font-weight:400;transition:transform .15s ease;
  }
  .size-pill-wrap .size-pill-toggle[aria-expanded="true"] .chev{ transform:rotate(180deg); }
  .size-pill-wrap .size-pill-note{ display:block;font-size:10.5px;color:var(--color-muted-text);margin:5px 2px 0; }

  .size-orientation-group{
    /* 開合改用transform+opacity做動畫（不用display:none切換），這樣才有辦法轉場；
       關閉時translateY(-120%)把面板滑出可視範圍上緣＋pointer-events:none避免擋住下面的內容，
       面板本身還是有layout（position:fixed不影響文件流），量測按鈕寬度不會再抓到0 */
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    position: fixed;           /* 跟分類下拉/選取框同一種修法，避免被.canvas-area的overflow裁切 */
    z-index: 60;
    left: 16px; right: 16px;
    background: color-mix(in srgb, var(--color-dark-base) 82%, white 18%);
    border-radius: 14px;
    padding: 16px;
    box-shadow: 0 10px 24px rgba(0,0,0,.35);
    display: flex;
    transform: translateY(-120%);
    opacity: 0;
    pointer-events: none;
    transition: transform 300ms ease-out, opacity 300ms ease-out;
  }
  .size-orientation-group.open{
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
  }
  .size-orientation-group .toolbar-row{
    width: auto;
    margin-bottom: 0;
    justify-content: flex-start;
  }
  #sizePanel .size-panel-group-label{
    display:block;font-size:11px;color:var(--color-interactive);letter-spacing:.05em;margin:0 0 -2px;font-weight:700;
  }
  .size-panel-note{ font-size:10.5px;color:rgba(245,239,198,.65);text-align:center;margin:2px 0 0; }
  #sizePanel .size-panel-confirm{
    display:block;width:100%;border:none;background:var(--color-primary-btn);color:#fff;
    border-radius:20px;padding:11px;font-size:13.5px;font-weight:700;cursor:pointer;margin-top:2px;
  }
  /* 首次進入排版頁面時，同一個#sizePanel改用置中彈窗的呈現方式，強制先選一次尺寸再開始排版。
     置中改用top:0;bottom:0;margin:auto（不佔用transform），這樣transform可以專心留給上面的開合動畫用，
     兩者才不會互相蓋掉對方（一個元素的transform只能有一個值，硬要疊加置中+開合會變成要手動組合calc()，不如分開兩種方式各司其職） */
  .size-orientation-group.first-entry{
    left:20px; right:20px; top:0; bottom:0; margin:auto;
    height:fit-content; max-height:calc(100% - 40px); overflow-y:auto;
  }
  /* 用#sizeScrim（ID優先度較高）而不是.size-scrim，避免被後面桌面版.size-scrim{display:none}
     蓋掉——這兩條優先度原本相同(都是單一class)，寫在後面的桌面規則會贏，導致這裡設的display:block
     其實從來沒真的生效過（電腦版computed style還是回報opacity/backdrop-filter正確，因為那些
     屬性在display:none底下還是算得出值，只是不會畫出來，這個坑之前修別的元件時也踩過一次） */
  #sizeScrim{
    display:block;position:fixed;inset:0;background:rgba(20,18,15,.55);z-index:55;
    -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px); /* 讓下拉選單/首次進入彈窗後面的畫面模糊，襯托選單本身 */
    opacity:0;pointer-events:none;transition:opacity 300ms ease-out;
  }
  #sizeScrim.open{ opacity:1;pointer-events:auto; }
  .grid-wrapper{
    max-width: 100%;
    overflow-x: auto;         /* 格子太寬時可以左右滑動看 */
  }
  .sidebar{
    position: relative;      /* 收合鈕用絕對定位貼齊標題右側，需要這一層當基準 */
  }
  .sidebar h1{
    max-width: calc(100% - 156px); /* 幫收合鈕（貼在標題右側）預留空間，最長分類名稱「上傳圖片」也要留得下，避免文字被蓋住 */
  }
  .tabs-wrap{
    margin-bottom: 16px;
  }
  /* 這幾條都用 .tabs-wrap 前綴提高優先度，避免被後面桌面版同名 class 的樣式蓋掉 */
  .tabs-wrap .tabs-toggle{
    display: flex;
    align-items: center;
    gap: 4px;
    position: absolute;      /* 貼到標題（.sidebar 內距頂端）右側，不佔原本版面高度 */
    top: 28px;                /* 對齊 .sidebar 的 padding-top，跟標題文字同一個起始高度 */
    right: 26px;               /* 對齊 .sidebar 的 padding-right */
    /* 原本用--pill-bg（深色底混白色算出來的衍生色），跟其他按鈕的顏色邏輯對不起來，
       改直接套用--color-primary-btn，看得出來這顆按鈕屬於「功能按鈕」這個色彩類別 */
    background: var(--color-primary-btn);
    color: #fff;
    border: none;
    border-radius: 20px;
    padding: 8px 12px;
    font-size: 12px;
    cursor: pointer;
    z-index: 51;
    transition: transform 100ms ease-out;
  }
  .tabs-wrap .tabs-toggle:active{ transform:scale(.96); }
  .tabs-wrap .tabs{
    display: none;            /* 預設收合，點擊收合鈕才展開 */
    position: fixed;          /* 用fixed而不是absolute，避免被.sidebar自己的max-height+overflow-y裁切
                                  （跟畫布裡的翻轉/刪除功能鍵、選取框是同一種修法） */
    top: 44px;                /* 實際值會在展開時由 JS 依收合鈕實際高度重新計算，這裡只是保底預設值 */
    right: 26px;               /* 貼齊收合鈕右緣，只設 right 不設 left，寬度就會依內容自動縮放 */
    min-width: 96px;           /* 分類名稱只有一兩個字時，避免選單看起來太窄 */
    max-width: calc(100% - 52px); /* 保底上限，避免未來分類名稱變長時撐出側邊欄 */
    width: max-content;
    flex-direction: column;   /* 展開後由上往下排列 */
    flex-wrap: nowrap;        /* 覆蓋桌面版的 flex-wrap:wrap，避免超過高度時被擠成多欄 */
    gap: 4px;
    margin-bottom: 0;
    background: color-mix(in srgb, var(--color-dark-base) 82%, white 18%);
    border-radius: 12px;
    padding: 8px;
    max-height: 40vh;
    overflow-y: auto;         /* 分類太多時可以在選單內捲動 */
    z-index: 50;
    box-shadow: 0 8px 24px rgba(0,0,0,.35);
  }
  .tabs-wrap .tabs.open{
    display: flex;            /* 展開狀態 */
  }
  .tabs-wrap .tabs .tab{
    width: 100%;              /* 相對於選單本身（已經是縮放後的寬度）撐滿，讓每個按鈕一樣寬 */
    white-space: nowrap;
    text-align: left;
  }

  /* 功能面板（翻轉/調整解析度/刪除/上下左右微調）手機版改成固定貼在螢幕左邊緣的一整排直式按鈕，
     不再跟著選取的圖案浮動移動；桌面版維持原本「貼著圖案旁邊」的浮動面板不變（見js/canvas.js
     positionToolbar()，該函式在手機版寬度時會直接return、不計算left/top，改由這裡的CSS決定位置）。
     用#itemToolbar前綴提高優先度，避免被後面桌面版同名class規則蓋掉（同一種踩過很多次的坑，
     跟.tabs-wrap .tabs-toggle是同樣的原因）。 */
  #itemToolbar{
    left: 6px;
    top: 50%;
    transform: translateY(-50%);
    max-height: calc(100vh - 16px); /* 8顆按鈕直排在矮螢幕（例如橫式手機）可能超出畫面高度，超過就自己捲動 */
    overflow-y: auto;
  }
  #itemToolbar .toolbar-actions{
    flex-direction: column;
  }
  #itemToolbar .nudge-pad{
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  #itemToolbar .nudge-pad button{
    border-radius: 7px;       /* 原本圓形按鈕排成十字形，現在跟其他按鈕一起直排，改回統一的圓角方形 */
  }
  /* 用#itemToolbar前綴（跟上面幾條同樣的理由），確保優先度贏過下面桌面版的.toolbar-sep{display:none}，
     不然兩條選擇器優先度打平時，寫在後面的桌面規則會贏，導致手機版分隔線一直不會顯示
     （這個坑在這個檔案已經踩過好幾次，這次直接照既有修法處理，不再犯） */
  #itemToolbar .toolbar-sep{
    display: block;
    height: 1px;
    background: rgba(255,255,255,.2);
    margin: 2px 3px;
  }
}
.toolbar-sep{ display:none; } /* 桌面版維持原本兩組（翻轉/刪除、方向鍵）分開的浮動面板樣式，不需要分隔線 */
  :root{
    --sidebar-bg:var(--color-dark-base);
    --sidebar-text:var(--color-light-text);
    --main-bg:var(--color-light-bg);
    --accent:#ffffff;
    --pill-bg:color-mix(in srgb, var(--color-dark-base) 75%, white 25%);
    --line:#d8d3c4;
    --toolbar-button-size:30px;
  }
  /* touch-action:manipulation 讓整個手機版都不會有雙擊放大整頁的手勢，
     不只是任務14修過的按鈕，這裡直接套用在每個元素上，一次解決全站的問題 */
  *{box-sizing:border-box;touch-action:manipulation;}
  /* 任務21：手機long press不要跳出瀏覽器原生「拷貝/尋找所選範圍/查詢」選單或藍色選取控制點。
     input/textarea排除在外，讓輸入欄位還是能正常選字編輯（例如姓名、日期欄位）。 */
  *{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;}
  input,textarea{-webkit-touch-callout:default;-webkit-user-select:text;user-select:text;}
  body{margin:0;font-family:"Noto Serif TC","Helvetica Neue",Arial,sans-serif;color:#222;}
  button,input,select,textarea{font-family:"LXGW WenKai TC","Noto Serif TC","Helvetica Neue",Arial,sans-serif;}
  .app{display:flex;min-height:100vh;}

  /* ---------- 簡介頁（首頁）：控制在手機一屏內看完，不用捲動 ---------- */
  .intro-screen{
    display:flex;align-items:center;justify-content:center;
    min-height:100vh;min-height:100dvh;
    background:var(--color-dark-base);padding:20px;
  }
  .intro-card{
    max-width:420px;width:100%;text-align:center;
    display:flex;flex-direction:column;gap:10px;
  }
  .intro-header{
    position:relative;display:flex;align-items:center;justify-content:center;gap:12px;
  }
  .intro-logo-lockup{ display:flex;align-items:center;gap:8px; }
  .intro-logo-icon{ height:36px;width:auto;display:block; }
  .intro-ig-link{
    position:absolute;right:0;top:50%;transform:translateY(-50%);
    display:flex;align-items:center;justify-content:center;
    width:44px;height:44px;border-radius:50%;color:#555;flex-shrink:0;
  }
  .intro-ig-link:hover{ color:var(--color-brand); }
  .intro-card h1{
    font-family:"Noto Serif TC",Georgia,serif;font-weight:700;font-size:22px;margin:0;color:var(--color-interactive);
  }
  .intro-tagline{ font-size:15px;font-weight:600;color:var(--color-interactive);margin:0; }
  .intro-desc{ font-size:13px;line-height:1.7;color:var(--color-light-text);margin:6px 0 0; }
  .intro-pricing{
    background:#fff;border:1px solid var(--line);border-radius:14px;
    padding:12px 16px;margin:8px 0 0;display:flex;flex-direction:column;gap:6px;
  }
  .intro-price-row{
    display:flex;align-items:baseline;justify-content:space-between;font-size:13px;color:#222;
  }
  .intro-price-note{ font-size:11px;color:var(--color-muted-text); }
  .intro-warning{ font-size:11px;color:var(--color-muted-text);margin:0;line-height:1.6; }
  .intro-start-btn{
    margin-top:8px;background:rgba(var(--color-primary-btn-rgb),0.85);color:#fff;border:none;
    border-radius:26px;padding:14px 20px;font-size:15px;font-weight:600;cursor:pointer;
    min-height:44px;align-self:center;
  }
  .intro-start-btn:hover{ background:rgba(var(--color-primary-btn-rgb),1); }
  .app[hidden]{ display:none; }

  /* ---------- 左側欄 ---------- */
  .sidebar{
    width:340px;flex-shrink:0;background:var(--sidebar-bg);color:var(--sidebar-text);
    padding:28px 26px;display:flex;flex-direction:column;
    color-scheme:dark; /* 側邊欄底色變深之後，瀏覽器原生捲軸的淺色滑塊對比太明顯，
                           用這個屬性讓捲軸自動改用適合深色底的樣式，不用另外刻webkit捲軸樣式 */
  }
  .sidebar h1{font-family:"Noto Serif TC",Georgia,serif;font-weight:700;font-size:20px;margin:0 0 8px;color:var(--color-interactive);}
  .sidebar p{font-size:12px;line-height:1.6;opacity:.9;margin:0 0 10px;color:var(--color-interactive);}

  .tabs-toggle{ display:none; } /* 桌面版維持原本展開列表，收合按鈕只在手機版顯示 */
  /* 任務25：桌面版空間充足，維持原本常駐展開的尺寸/方向選單，收合pill/提示/確認鈕/遮罩都只在手機版才出現 */
  .size-pill-toggle,.size-pill-note,.size-panel-confirm,.size-scrim,.size-panel-group-label{ display:none; }
  .tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px;}
  .tab{
    background:var(--pill-bg);border:none;color:var(--color-interactive);
    padding:8px 14px;border-radius:20px;font-size:13px;cursor:pointer;
    transition:background-color .15s ease, transform 100ms ease-out;
  }
  .tab.active{background:var(--accent);color:var(--color-interactive);}
  .tab:hover{background:var(--color-interactive);color:var(--color-warning);}
  .tab:active{ transform:scale(.96); }

  .icon-grid{
    /* 用auto-fill+minmax，欄數依實際可用寬度自動調整，不寫死欄數，
       手機/電腦共用同一條規則，兩邊排版一定會保持一致，不會各自改壞 */
    display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));
    grid-auto-rows:min-content;gap:8px;
    overflow-y:auto;padding-top:10px;border-top:1px solid rgba(255,255,255,.15);
  }
  .hangul-composer{
    padding:10px 0;margin-bottom:4px;border-bottom:1px solid rgba(255,255,255,.15);
  }
  .hangul-composer-row{ display:flex;gap:6px;margin-bottom:8px; }
  .hangul-select{
    flex:1;min-width:0;background:color-mix(in srgb, var(--color-dark-base) 82%, white 18%);color:var(--sidebar-text);
    border:1px solid rgba(255,255,255,.2);border-radius:6px;padding:5px 2px;font-size:12px;
  }
  .icon-btn.hangul-preview-btn{ width:100%; aspect-ratio:auto; } /* 取消.icon-btn的正方形設定（用複合選擇器確保優先度贏過.icon-btn），這格維持原本依內容決定高度 */
  .icon-btn{
    position:relative;
    min-width:0;min-height:0;       /* 預設min-height:auto會讓內容需要的高度贏過aspect-ratio，這裡歸零 */
    aspect-ratio:1/1;               /* 改成正方形，寬高一致 */
    background:transparent;border:1px solid var(--color-interactive);border-radius:8px;
    padding:6px 4px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
    font-size:11px;cursor:pointer;overflow:hidden;
    transition:background-color .15s ease, transform 100ms ease-out;
  }
  .icon-btn:hover{
    background:var(--color-interactive);
  }
  .icon-btn:active{ transform:scale(.94); }
  .icon-btn .glyph-label{font-size:12px;color:var(--color-interactive);transition:color .15s ease;}
  .icon-btn:hover .glyph-label{color:var(--color-warning);}
  .icon-delete-btn{
    position:absolute;top:-6px;right:-6px;width:18px;height:18px;border-radius:50%;
    background:rgba(var(--color-warning-rgb),0.75);color:#fff;font-size:12px;line-height:1;
    display:flex;align-items:center;justify-content:center;cursor:pointer;
  }
  .icon-delete-btn:hover{ background:color-mix(in srgb, var(--color-warning) 90%, white 10%); }
.icon-preview{display:flex;align-items:center;justify-content:center;width:28px;height:28px;}
.icon-preview svg{width:100%;height:100%;}
.upload-btn{ border-style:dashed; border-color:rgba(255,255,255,.3); }
.upload-btn .icon-preview{ font-size:18px; }
.grid-wrapper{ position:relative; }
.item-toolbar{
  position:fixed;
  display:none;
  flex-direction:column;
  align-items:center;
  gap:6px;
  /* 任務26：面板本身已經是半透明橄欖綠背景，加上backdrop-filter就變成「有顏色的毛玻璃」，
     跟選取框的無色玻璃呼應但保留品牌色調；上面的按鈕本身維持實色（不是透明），
     確保翻轉/刪除/方向鍵的圖示在任何背景下都夠清楚好點擊，不會因為玻璃感犧牲可操作性 */
  background:rgba(var(--color-primary-btn-rgb),0.85);
  -webkit-backdrop-filter:blur(6px);
  backdrop-filter:blur(6px);
  border:1px solid rgba(255,255,255,0.25);
  padding:4px;
  border-radius:6px;
  box-shadow:0 2px 8px rgba(0,0,0,.3);
  z-index:500;
}
.toolbar-actions{ display:flex; gap:4px; }
.nudge-pad{
  display:grid;
  grid-template-columns:25px 25px 25px;
  grid-template-rows:25px 25px 25px;
  gap:2px;
}
/* 上下左右微調鍵改用--color-interactive（藍色，全站選取/互動語意的顏色），
   跟翻轉/調整解析度的中性淺灰做出區隔，一眼就能分出「這組是移動控制」 */
.item-toolbar .nudge-pad button{
  width:25px;height:25px;border:none;border-radius:50%;
  background:var(--color-interactive);color:#fff;cursor:pointer;padding:0;
  display:flex;align-items:center;justify-content:center;
}
.item-toolbar .nudge-pad button:hover{ background:color-mix(in srgb, var(--color-interactive) 85%, white 15%); }
.nudge-up{ grid-column:2; grid-row:1; }
.nudge-left{ grid-column:1; grid-row:2; }
.nudge-right{ grid-column:3; grid-row:2; }
.nudge-down{ grid-column:2; grid-row:3; }
.selection-frame{
  position:fixed;
  display:none;
  border:2px solid rgba(var(--color-primary-btn-rgb),0.85);
  /* 任務26之前這裡還有一個 0 0 0 9999px 的巨大box-shadow，本來想營造「其餘畫面變暗、只留選取範圍清楚」
     的聚光燈效果，但顏色(250,248,244)只有在畫布米色背景上才勉強不明顯，一旦選取框出現在側邊欄/按鈕
     等其他色塊區域，會整頁蒙上一層很醜的灰白霧，跟這次毛玻璃卡片的效果衝突，所以拿掉，
     改成單純卡片本身的立體陰影 */
  box-shadow:0 2px 10px rgba(0,0,0,.15);
  pointer-events:none;
  z-index:400;
  border-radius:2px;
}
/* 任務26原本在選取框「外面」加毛玻璃霧面襯托，後來使用者回饋改成更直接的做法：
   選取的圖案本身直接變色（見js/canvas.js的paintAll，套用PREVIEW_COLOR），
   不用另外算一個毛玻璃遮罩的clip-path，.canvas-glass-overlay整組（HTML/CSS/JS）已經拿掉 */
/* 原本這裡預設用color-mix(dark-base混白)當按鈕底色，跟面板本身的--color-primary-btn背景
   明暗度太接近（就是colors.css裡註記過的那個「深色三兄弟對比度偏低」問題），手機版點進去看
   完全分不出按鈕在哪裡。改成跟翻轉/方向鍵一樣統一用淺色底(--color-light-text)+深色字，
   確保面板上每一顆按鈕都跟深色面板背景有明顯區隔，不用再另外為個別按鈕加例外規則 */
.item-toolbar button{
  width:var(--toolbar-button-size);height:var(--toolbar-button-size);
  border:none;border-radius:4px;
  background:var(--color-light-text);color:var(--color-dark-base);
  font-size:14px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
}
.item-toolbar button:hover{ background:#e0ddd0; }
.item-toolbar button.danger{ background:rgba(var(--color-warning-rgb),0.85);color:#fff; }
.item-toolbar button.danger:hover{ background:color-mix(in srgb, var(--color-warning) 85%, white 15%); }
/* 使用者反饋：--color-warning現在是深藍灰色，「刪除圖案」這種真正的警示動作看不太出來，
   垃圾桶這裡改用實際的紅色（沿用js/canvas.js裡ERASE_PREVIEW_COLOR同一支紅），只有這一個
   按鈕例外，不動--color-warning本身，避免影響全站其他用到warning語意的地方 */
#deleteItemBtn{ background:rgba(192,57,43,0.85); }
#deleteItemBtn:hover{ background:rgba(192,57,43,1); }
  .icon-btn.selected{border-color:var(--color-interactive);background:color-mix(in srgb, var(--color-dark-base) 70%, white 30%);}

  /* ---------- 右側畫布區 ---------- */
  .canvas-area{
    flex:1;padding:24px 32px;overflow:auto;position:relative;
    /* 畫布後面的底色使用者指定用--color-light-bg（dcdcd1米灰白），
       跟--color-interactive（icon-btn框線/hover等強調色用途）分開，不然兩者都用interactive會互相影響 */
    background-color:var(--color-light-bg);
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.08'/%3E%3C/svg%3E");
    background-repeat:repeat;
  }
  .toolbar-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px;}
  .toolbar-row.right{justify-content:flex-end;}
  .pill-btn{
    background:#fff;border:1px solid var(--line);padding:8px 16px;border-radius:20px;
    font-size:13px;cursor:pointer;
  }
  .pill-btn.active{background:rgba(var(--color-primary-btn-rgb),0.85);color:#fff;border-color:rgba(var(--color-primary-btn-rgb),0.85);}
  .segmented-control{
    position:relative;display:inline-flex;background:#fff;border:1px solid var(--line);
    border-radius:20px;padding:3px;
  }
  .segmented-control button{
    position:relative;z-index:1;border:none;background:transparent;padding:8px 16px;
    border-radius:20px;font-size:13px;cursor:pointer;color:#222;transition:color .2s;
  }
  .segmented-control button.active{ color:#fff; }
  .segmented-slider{
    position:absolute;top:3px;left:3px;height:calc(100% - 6px);border-radius:20px;
    background:rgba(var(--color-primary-btn-rgb),0.85);transition:transform .25s ease, width .25s ease;z-index:0;
  }
  .price-note{ font-size:11px;color:var(--color-muted-text);margin-left:8px; }
  .current-price-label{
    display:inline-block;background:#fff;border:1px solid var(--line);
    padding:6px 14px;border-radius:20px;font-size:12px;color:#555;
  }
  .action-btn{
    margin-left:auto;background:#fff;border:1px solid var(--line);padding:8px 18px;
    border-radius:20px;font-size:13px;cursor:pointer;
    /* 沒有明確設定color的話，iOS Safari的<button>預設會用系統藍色調（不是繼承body的文字色），
       電腦版瀏覽器不會有這個問題，所以之前沒發現。-webkit-appearance:none把系統原生按鈕外觀
       整個關掉，避免類似的樣式被系統預設值蓋過去 */
    color:#222;-webkit-appearance:none;appearance:none;
    /* 任務17：按下去的觸感回饋，只用transform（GPU加速），不影響版面 */
    transition:transform 100ms ease-out;
  }
  .action-btn:active{ transform:scale(.96); }

  /* 工具列圖示hover微動效：只在真的有滑鼠、能hover的裝置上生效（觸控裝置點擊後會卡在:hover
     狀態，效果會變得很奇怪，用(hover:hover)排除），每個圖示依造型設計不同的動作，不是統一套用同一種效果 */
  @media (hover:hover) and (pointer:fine){
    .action-btn svg{ transition:transform 200ms ease-out; }
    #undoBtn:hover svg{ transform:rotate(-20deg); }
    #magnifyBtn:hover svg{ transform:scale(1.15); }

    @keyframes icon-wiggle{ 0%,100%{ transform:rotate(-9deg); } 50%{ transform:rotate(9deg); } }
    #eraserBtn:hover svg,#paintBtn:hover svg{ animation:icon-wiggle 300ms ease-in-out; }

    /* 垃圾桶只讓「蓋子橫線＋提把」（第1、3條path）掀開，桶身（第2條path）不動 */
    #clearBtn svg path{ transition:transform 220ms ease-out; transform-box:fill-box; transform-origin:left center; }
    #clearBtn:hover svg path:nth-child(1),
    #clearBtn:hover svg path:nth-child(3){ transform:rotate(-15deg); }

    /* 下載箭頭只讓「箭身＋箭頭」（第1、2條path）往下滑，托盤底線（第3條path）不動 */
    #exportBtn svg path{ transition:transform 200ms ease-out; }
    #exportBtn:hover svg path:nth-child(1),
    #exportBtn:hover svg path:nth-child(2){ transform:translateY(2px); }

    /* 功能面板（翻轉/調整解析度/刪除/上下左右微調），跟上面同一套「依圖示造型設計動作」原則 */
    #flipHBtn svg,#flipVBtn svg,#resizeItemBtn svg{ transition:transform 200ms ease-out; }
    @keyframes flip-h-wiggle{ 0%,100%{ transform:scaleX(1); } 50%{ transform:scaleX(-1); } }
    @keyframes flip-v-wiggle{ 0%,100%{ transform:scaleY(1); } 50%{ transform:scaleY(-1); } }
    @keyframes resize-pulse{ 0%,100%{ transform:scale(1); } 50%{ transform:scale(.78); } }
    #flipHBtn:hover svg{ animation:flip-h-wiggle 350ms ease-in-out; }
    #flipVBtn:hover svg{ animation:flip-v-wiggle 350ms ease-in-out; }
    #resizeItemBtn:hover svg{ animation:resize-pulse 300ms ease-in-out; }

    /* 刪除圖案的垃圾桶，跟#clearBtn同樣的「蓋子掀開」手法，但這顆按鈕的SVG結構不同
       （第1個子元素是polyline不是path），蓋子/提把是第1、3個子元素，桶身(含中間兩條rib線)不動 */
    #deleteItemBtn svg *{ transition:transform 220ms ease-out; transform-box:fill-box; transform-origin:left center; }
    #deleteItemBtn:hover svg polyline:nth-child(1),
    #deleteItemBtn:hover svg path:nth-child(3){ transform:rotate(-15deg); }

    /* 上下左右微調鍵：往按下去會移動的方向輕輕探出去，跟翻轉/調整解析度的動作類型不同（位移vs縮放/翻轉），
       行為上也呼應「這顆按鈕是做什麼的」 */
    .nudge-pad button svg{ transition:transform 180ms ease-out; }
    .nudge-up:hover svg{ transform:translateY(-2px); }
    .nudge-down:hover svg{ transform:translateY(2px); }
    .nudge-left:hover svg{ transform:translateX(-2px); }
    .nudge-right:hover svg{ transform:translateX(2px); }
  }
  .action-btn.primary{background:rgba(var(--color-primary-btn-rgb),0.85);color:#fff;border-color:rgba(var(--color-primary-btn-rgb),0.85);}
  .action-btn.eraser-default{background:rgba(var(--color-primary-btn-rgb),0.15);color:var(--color-primary-btn);border-color:rgba(var(--color-primary-btn-rgb),0.35);}
  .action-btn.eraser-active{background:rgba(var(--color-warning-rgb),0.45);color:#fff;border-color:rgba(var(--color-warning-rgb),0.45);}
  .action-btn.danger{background:rgba(var(--color-warning-rgb),0.85);color:#fff;border-color:rgba(var(--color-warning-rgb),0.85);}
  .action-btn.danger:hover{background:rgba(var(--color-warning-rgb),1);}
  /* 工具列的「清空畫布」觸發鈕：用跟單格去除啟用中同一種半透明紅，比彈窗裡「確定清空」淡一些 */
  .action-btn.danger-soft{background:rgba(var(--color-warning-rgb),0.45);color:#fff;border-color:rgba(var(--color-warning-rgb),0.45);}
  .action-btn.danger-soft:hover{background:rgba(var(--color-warning-rgb),0.6);}
  .confirm-actions{display:flex;gap:10px;}
  .confirm-actions .action-btn{flex:1;margin-left:0;}
  .zoom-control{display:flex;align-items:center;gap:6px;margin-left:auto;}
  .zoom-control .action-btn{margin-left:0;}
  /* ---------- 輸出前的「填寫預約資訊」彈窗：使用者指定的例外設計，復古打字機收據風格，
     跟全站其他彈窗共用的.help-card「工藝標本卡」樣式脫鉤，只有這一個表單這樣做。
     字體用Special Elite（index.html的Google Fonts已加），奶油色收據紙配深咖啡色墨水字，
     跟colors.css的全站色票無關，是刻意的一次性例外（跟垃圾桶紅色、方向鍵藍色是同一種例外邏輯）。 */
  .receipt-card{
    position:relative;
    /* isolation:isolate強制這裡自成一個獨立的堆疊環境，不然下面.receipt-grain的z-index:-1
       會直接跟頁面其他層（例如.help-overlay的深色背景）比較，結果被壓到整個網站背景下面、
       完全看不到，而不是只沉到這張卡片自己的文字內容下面 */
    isolation:isolate;
    width:320px;max-width:100%;
    background:#f2ecd9;color:var(--color-interactive);
    /* Google Fonts沒有真正的中文打字機字體（中文打字機歷史上是機械選字，不是像英文
       一鍵一字敲擊，沒有發展出對應的字體視覺傳統）。改成Special Elite負責英文/數字，
       LXGW WenKai TC接手中文——瀏覽器字型後備機制會自動依照每個字元找字型堆疊裡
       第一個「有這個字的字符集」的字型，不用另外寫規則分開處理 */
    font-family:"Special Elite","LXGW WenKai TC","Courier New",monospace;
    /* 左右padding加大，讓內文比卡片本身窄一截，比較有「紙本身比印刷範圍寬」的感覺 */
    padding:32px 40px 26px;
    /* 雙層陰影：一層貼近邊緣的小範圍深色陰影營造實際厚度，一層大範圍柔和陰影營造懸浮感，
       兩層疊加比單一陰影更有「真的放在桌上/離開螢幕表面」的實體感 */
    box-shadow:
      0 2px 6px rgba(0,0,0,.4),
      0 26px 60px rgba(0,0,0,.4);
    text-align:left;
    opacity:0;
    transform:translateY(8px);
    transition:opacity 220ms ease-out, transform 220ms ease-out;
    overflow:hidden; /* 配合下面的紙張紋理，紋理鋪滿整張卡片，超出撕邊範圍的部分裁掉 */
  }
  .help-overlay.open .receipt-card{ opacity:1;transform:translateY(0); }
  /* 使用者要求把階梯形缺角票卡取消、改回原本的鋸齒撕邊造型 */
  .receipt-card::before,.receipt-card::after{
    content:"";position:absolute;left:0;right:0;height:10px;z-index:2;
    background:
      linear-gradient(135deg, transparent 50%, #f2ecd9 50%) 0 0/13px 13px repeat-x,
      linear-gradient(-135deg, transparent 50%, #f2ecd9 50%) 0 0/13px 13px repeat-x;
  }
  .receipt-card::before{ top:-9px;transform:rotate(180deg); }
  .receipt-card::after{ bottom:-9px; }
  /* 紙張紋理：使用者反饋摺痕線太假，拿掉那個效果。改成疊兩種不同尺度的雜訊——
     一層細顆粒模擬紙纖維，一層大尺度、極低對比的雲霧狀雜訊模擬紙張本身厚薄不均勻，
     兩層疊加比單一尺度的雜訊更接近真實紙張「近看有顆粒、遠看有大範圍色調不均」的樣子。
     混合模式用multiply讓紋理自然融進紙面，不會蓋掉底色 */
  .receipt-grain{
    content:"";position:absolute;inset:0;pointer-events:none;z-index:-1;
    mix-blend-mode:multiply;
    /* 第1層：極輕微暗角(radial-gradient)，紙張本身厚薄/受光不均勻的感覺，四角只比中央深5%，
       維持很淡避免看起來像加了濾鏡。第2層：大尺度低對比雲霧狀雜訊，模擬紙張大範圍色調不均。
       第3層：細顆粒雜訊模擬紙纖維。三層疊加比單一尺度的雜訊更接近真實紙張的質感層次 */
    background-image:
      radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,.05) 100%),
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='340' height='340'%3E%3Cfilter id='n2'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.02' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n2)' opacity='0.35'/%3E%3C/svg%3E"),
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='130' height='130'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.22'/%3E%3C/svg%3E");
    background-size:100% 100%, 340px 340px, 130px 130px;
    background-repeat:no-repeat, repeat, repeat;
    opacity:.7;
  }
  /* 邊框改用不規則的手繪圓（4個角各給不同的圓角比例），不是完美正圓，
     再疊一圈微微偏移/旋轉、更淡的第二層邊框，模擬蓋印章時油墨不均、邊緣有點糊開的感覺 */
  .receipt-pending-badge{
    position:absolute;top:30px;right:20px;
    width:52px;height:52px;
    border-radius:47% 53% 51% 49% / 53% 47% 55% 45%;
    border:2px solid rgba(140,35,32,.55);color:rgba(140,35,32,.55);
    display:flex;align-items:center;justify-content:center;text-align:center;
    font-size:8.5px;letter-spacing:.04em;font-weight:700;line-height:1.4;
    transform:rotate(-16deg);
  }
  .receipt-pending-badge::before{
    content:"";position:absolute;inset:-3px;pointer-events:none;
    border:1.5px solid rgba(140,35,32,.28);
    border-radius:52% 48% 46% 54% / 44% 56% 48% 52%;
    transform:rotate(7deg);
  }
  .receipt-head{ text-align:center;margin-bottom:14px; }
  .receipt-mark{
    width:34px;height:34px;border-radius:50%;border:2px solid var(--color-interactive);margin:0 auto 8px;
    display:flex;align-items:center;justify-content:center;font-size:15px;
  }
  .receipt-shop{ font-size:15px;letter-spacing:.05em;margin:0 0 2px;font-weight:700; }
  .receipt-sub{ font-size:10px;letter-spacing:.2em;color:#6b6153;margin:0; }
  .receipt-rule{ width:80%;border:none;border-top:1.5px dashed #8a8066;margin:14px auto; }
  .receipt-rule.solid{ border-top-style:double;border-top-width:4px; }
  .receipt-lead{ font-size:10.5px;letter-spacing:.04em;color:#6b6153;margin:0 0 18px;text-align:center;line-height:1.8; }
  /* 網格分格的票根/館本樣式：每個欄位是一整排橫線分隔的row，label靠左窄欄（跟value欄用
     直線分開），取代原本每格獨立標籤+底線的排法。跟參考圖1、2的登機證/票根排版邏輯一樣 */
  .receipt-fields{
    display:flex;flex-direction:column;
    border-top:1.5px solid var(--color-interactive);border-bottom:1.5px solid var(--color-interactive);
  }
  .receipt-row{
    display:flex;align-items:center;gap:12px;padding:9px 0;
  }
  .receipt-row + .receipt-row{ border-top:1px solid rgba(58,50,38,.3); }
  .receipt-row label{
    flex:0 0 64px;font-size:9px;letter-spacing:.1em;text-transform:uppercase;color:#6b6153;
    font-weight:700;line-height:1.5;border-right:1px solid rgba(58,50,38,.25);padding-right:10px;
    align-self:stretch;display:flex;align-items:center;
  }
  .receipt-row-value{ flex:1;min-width:0;font-size:14px;line-height:1.5; }
  .receipt-input{
    width:100%;background:transparent;border:none;
    border-radius:0;padding:2px 0;font-size:14px;color:var(--color-interactive);
    font-family:inherit;transition:color .15s ease;
  }
  .receipt-input:focus{ outline:none; }
  .receipt-input.missing{ color:#8c2320; }
  .receipt-hint{ display:block;font-size:9px;color:#9a917f;line-height:1.6;margin-top:3px; }
  /* 使用者拼貼完成的圖案，用像素點陣的方式印在收據上，像真的收據機印出來的感覺，
     每個人的設計都長不一樣，這張收據才會有「這是我自己的作品」的獨特感。
     使用者指定：拿掉文字說明、圖案移到基本資料上面、面積要比欄位區塊大，是收據的主角；
     不要歪斜、不要框、不要底色，只留圖案本身直接印在紙上 */
  .receipt-preview-wrap{ text-align:center;margin:4px 0 36px;display:flex;justify-content:center; }
  .receipt-preview-canvas{
    display:block;max-width:100%;height:auto;image-rendering:pixelated;
    background:transparent;
  }
  .receipt-barcode{
    height:26px;margin:16px 0 5px;position:relative;
    background:repeating-linear-gradient(90deg,var(--color-interactive) 0 2px,transparent 2px 5px, var(--color-interactive) 5px 6px, transparent 6px 9px, var(--color-interactive) 9px 12px, transparent 12px 14px);
  }
  /* 條碼疊一層雜訊當印刷瑕疵，讓每一條線深淺不完全一致，不是印表機等級的精準乾淨線條，
     混合模式用overlay（不是multiply）才會同時有變深跟變淺的地方，看起來像油墨濃淡不均 */
  .receipt-barcode::before{
    content:"";position:absolute;inset:0;pointer-events:none;mix-blend-mode:overlay;opacity:.6;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='50' height='26'%3E%3Cfilter id='bn'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.3 0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23bn)'/%3E%3C/svg%3E");
    background-repeat:repeat-x;
  }
  .receipt-barcode-num{ text-align:center;font-size:9.5px;letter-spacing:.2em;color:#6b6153; }
  .receipt-error{ display:block;color:#8c2320;font-size:12px;min-height:16px;text-align:center;margin-top:10px; }
  .receipt-actions{ display:flex;gap:10px;margin-top:18px;justify-content:center; }
  .receipt-btn{
    flex:1;max-width:112px;font-family:inherit;font-size:11px;letter-spacing:.06em;text-transform:uppercase;font-weight:700;
    cursor:pointer;padding:8px 10px;background:transparent;
    transition:transform 120ms ease-out, background-color 120ms ease-out;
  }
  /* 印章感只留一點點歪斜就好，太明顯的旋轉角度看起來像壞掉、對不齊，不是故意做舊 */
  .receipt-btn.cancel{ border:2px double #6b6153;color:#6b6153;transform:rotate(-0.5deg); }
  .receipt-btn.confirm{
    border:3px double #8c2320;color:#8c2320;transform:rotate(0.5deg);position:relative;
  }
  .receipt-btn.confirm::after{
    content:"";position:absolute;inset:3px;border:1px solid #8c2320;opacity:.4;pointer-events:none;
  }
  .receipt-btn:active{ transform:scale(.94) rotate(0deg) !important; }
  .receipt-btn:disabled{ opacity:.35;cursor:default; }
  /* 任務18：輸入框改成底線式（不是方框），標籤改成細字追蹤大寫，欄位間距加大。
     使用者要求填寫表單改回這套「工藝標本卡」風格（跟收據.receipt-*樣式分開），方便打字 */
  .export-field{
    display:flex;flex-direction:column;gap:6px;
  }
  .export-field label{
    font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--color-muted-text);
    padding-left:0;font-family:"LXGW WenKai TC","Noto Serif TC",serif;
  }
  .export-input{
    background:transparent;border:none;border-bottom:1px solid rgba(var(--color-dark-base-rgb),.3);
    border-radius:0;padding:5px 2px 8px;font-size:14px;color:#222;
    transition:border-color .15s ease;
  }
  .export-input:focus{ outline:none;border-bottom-color:var(--color-primary-btn); }
  .export-input.missing{ border-bottom-color:var(--color-warning); }
  .export-field-hint{ font-size:10.5px;color:var(--color-muted-text);line-height:1.6;padding-left:0;margin-top:2px; }
  .export-error{ color:var(--color-warning); font-size:13px; min-height:18px; }
  .export-form-fields{
    display:flex;flex-direction:column;gap:20px;text-align:left;margin-bottom:6px;
  }
  .export-form-fields .export-input{ width:100%; }
  .action-btn:disabled{ opacity:.4;cursor:default; }

  .grid-wrapper{display:inline-block;max-width:100%;border:2px solid rgba(var(--color-primary-btn-rgb),0.85);background:#fff;overflow:auto;max-height:70vh;padding:0;}
  .zoom-viewport{overflow:hidden;}
  .stitch-grid{display:grid;}
  .cell{
    border:1px solid #e6e2d6;display:flex;align-items:center;justify-content:center;
    font-size:14px;cursor:pointer;user-select:none;
  }
  .cell:hover{background:#f2efe4;}
  .cell.filled{background:#222;}
  .cell.grid-major-right{ border-right:2px solid #b8b09a; }
  .cell.grid-major-bottom{ border-bottom:2px solid #b8b09a; }

  .help-btn{
    position:fixed;bottom:20px;right:20px;width:42px;height:42px;border-radius:50%;
    background:#222;color:#fff;border:none;font-size:16px;cursor:pointer;
    z-index:600;
  }

  /* ---------- 任務18：彈窗質感優化，「工藝標本卡」風格 ----------
     全站6個彈窗（教學/確定清空/韓文防呆/輸出表單/輸出完成/解析度選擇）共用同一套.help-*樣式，
     顏色全部引用colors.css既有變數，沒有另外定義新色碼。 */
  /* 任務17：彈窗開合改用opacity+visibility切換（不再用display:none），這樣才有辦法做淡入淡出動畫。
     元素常駐DOM（跟#sizeScrim同一套做法），position:fixed本來就不佔版面空間，關閉時pointer-events:none
     避免擋住底下畫面的點擊。visibility延遲切換是為了關閉動畫播完之前，彈窗還是要保持不可點擊。 */
  .help-overlay{
    position:fixed;inset:0;
    /* 只要毛玻璃模糊感，不要色調——改用中性黑色極低透明度，不用--color-dark-base（會染出紅棕色調） */
    background:rgba(0,0,0,.22);
    -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
    display:flex;justify-content:center;
    /* flexbox置中+overflow:auto有個常見坑：內容比容器高時，用一般的align-items:center，
       瀏覽器只會在「下面」多出可捲動的空間，「上面」超出的部分反而捲不到、永遠被裁掉看不到
       （因為置中造成的上下溢出，瀏覽器預設只把捲動空間留給後面那一側）。
       收據彈窗欄位變多之後高度常常超過螢幕，才踩到這個坑。改用align-items:safe center，
       瀏覽器發現內容放不下時會自動退回貼齊頂端對齊，確保整個彈窗從頭到尾都能捲動看到，
       不支援safe/unsafe關鍵字的舊瀏覽器會直接忽略這行、繼續用上面那行原本的center */
    align-items:center;
    align-items:safe center;
    z-index:700;padding:20px;overflow-y:auto; /* 內容較長的彈窗（例如輸出表單）在矮螢幕上還是能捲動看到底部按鈕 */
    opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity 200ms ease-out, visibility 0s linear 200ms;
  }
  .help-overlay.open{
    opacity:1;visibility:visible;pointer-events:auto;
    transition:opacity 200ms ease-out, visibility 0s linear 0s;
  }
  .help-card{
    background:var(--color-light-bg);border:1px solid rgba(var(--color-dark-base-rgb),.15);
    border-radius:10px;max-width:360px;width:100%;
    padding:26px 26px 22px;position:relative;
    box-shadow:0 24px 40px -12px rgba(var(--color-dark-base-rgb),.35);
    text-align:left;
    /* 卡片淡入+輕微上移8px，跟遮罩同時開始但獨立控制時間，感覺比純淡入更有「浮現」的層次感 */
    opacity:0;transform:translateY(8px);
    transition:opacity 220ms ease-out, transform 220ms ease-out;
  }
  .help-overlay.open .help-card{ opacity:1;transform:translateY(0); }
  .help-card.centered{ text-align:center; }
  .help-close{
    position:absolute;top:14px;right:14px;width:26px;height:26px;border-radius:50%;
    background:none;border:none;display:flex;align-items:center;justify-content:center;
    font-size:15px;color:var(--color-muted-text);cursor:pointer;line-height:1;padding:0;
    transition:background-color .15s ease, transform 100ms ease-out;
  }
  .help-close:hover{ background:rgba(var(--color-dark-base-rgb),.08);color:#222; }
  .help-close:active{ transform:scale(.9); }

  /* 圓形深色徽章：取代原本的emoji，裡面放線條風格SVG icon，疊一層極淡雜訊紋理增加質感 */
  .help-medallion-row{ display:flex;align-items:center;gap:14px;margin-bottom:14px; }
  .help-medallion{
    flex:none;width:48px;height:48px;border-radius:50%;
    background-color:var(--color-dark-base);
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.35'/%3E%3C/svg%3E");
    color:var(--color-light-text);
    display:flex;align-items:center;justify-content:center;
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);
  }
  .help-card.centered .help-medallion{ margin:0 auto 14px; }
  /* 破壞性操作（清空畫布）用警示色徽章 */
  .help-medallion.warn{ background-color:var(--color-warning); }
  .help-medallion svg{ width:22px;height:22px;stroke:currentColor;fill:none; }

  .help-eyebrow{
    font-size:10px;letter-spacing:.12em;color:var(--color-muted-text);text-transform:uppercase;
    margin:0 0 3px;font-family:"LXGW WenKai TC","Noto Serif TC",serif;
  }
  .help-title{ font-size:16px;font-weight:700;color:#222;margin:0; }
  .help-card.centered .help-title{ margin-top:2px; }
  .help-rule{ height:1px;background:rgba(var(--color-dark-base-rgb),.14);margin:16px 0; }
  .help-desc{
    font-size:12.5px;line-height:1.8;color:#5a5346;margin:0 0 18px;
  }
  .help-desc.centered{ text-align:center; }

  .help-nav{ display:flex;align-items:center;justify-content:space-between;gap:10px; }
  .help-dots{ display:flex;align-items:center;gap:6px; }
  .help-dots span{
    width:6px;height:6px;border-radius:50%;background:rgba(var(--color-dark-base-rgb),.18);
    transition:all .15s ease;
  }
  .help-dots span.active{ background:var(--color-primary-btn);width:16px;border-radius:3px; }
  .help-nav-btn{
    width:30px;height:30px;border-radius:50%;flex:none;
    border:1px solid rgba(var(--color-dark-base-rgb),.2);background:transparent;color:#222;
    cursor:pointer;display:flex;align-items:center;justify-content:center;
    transition:background-color .15s ease, transform 100ms ease-out;
  }
  .help-nav-btn:hover{ background:rgba(var(--color-dark-base-rgb),.06); }
  .help-nav-btn:active:not(:disabled){ transform:scale(.9); }
  .help-nav-btn:disabled{ opacity:.3;cursor:default;background:none; }

  .res-preview-wrap{
    display:flex;justify-content:center;margin-bottom:14px;
  }
  #resPreviewCanvas{
    background:#fff;border:1px solid var(--line);border-radius:8px;
    image-rendering:pixelated;
  }
  .res-slider-row{
    display:flex;align-items:center;gap:10px;margin-bottom:10px;
  }
  .res-slider-row input[type="range"]{ flex:1; }
  .res-slider-row span{ font-size:12px;color:#555;white-space:nowrap;width:70px;text-align:right; }
  .cell[data-item-id]{ cursor: grab; }
.cell[data-item-id]:active{ cursor: grabbing; }
.flip-icon-vertical{ transform: rotate(90deg); }
.grid-wrapper.eraser-mode .cell{ cursor: crosshair; }

/* ---------- 任務19方向B：手機版「放大檢視」彈窗 ----------
   用途單純只是「用比較大的畫面檢視/微調已經排好的圖案」，不能在裡面選新圖案、
   不能調整縮放（固定用能撐滿彈窗的最大尺寸顯示）、也不能清空畫布，
   只留單格去除，跟移動圖案要用的操作（拖曳、翻轉、刪除、上下左右微調，這些都在item-toolbar裡本來就有）。 */
.magnify-btn{ display:none; align-items:center; gap:6px; }
@media (max-width:900px){
  .magnify-btn{ display:inline-flex; }
}
/* 任務17：跟.help-overlay同一套開合邏輯，但改用縮放（0.96→1）取代位移，
   因為這個彈窗接近全螢幕，位移8px感覺不明顯，縮放比較有「展開進入」的感覺 */
.magnify-overlay{
  display:flex;position:fixed;inset:0;background:rgba(20,18,15,.7);
  z-index:800;padding:10px;
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity 200ms ease-out, visibility 0s linear 200ms;
}
.magnify-overlay.open{
  opacity:1;visibility:visible;pointer-events:auto;
  transition:opacity 200ms ease-out, visibility 0s linear 0s;
}
.magnify-inner{
  flex:1;min-width:0;background:var(--main-bg);border-radius:16px;
  display:flex;flex-direction:column;overflow:hidden;position:relative;
  transform:scale(.96);transition:transform 220ms ease-out;
}
.magnify-overlay.open .magnify-inner{ transform:scale(1); }
.magnify-close{
  position:absolute;top:10px;right:10px;z-index:5;width:34px;height:34px;border-radius:50%;
  background:#222;color:#fff;border:none;font-size:15px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  transition:transform 100ms ease-out;
}
.magnify-close:active{ transform:scale(.9); }
.magnify-tools-slot{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:14px 54px 10px 14px;
}
.magnify-canvas-slot{
  flex:1;min-height:0;overflow:auto;padding:10px 14px 14px;
  display:flex;align-items:flex-start;justify-content:center;
}
.magnify-canvas-slot .grid-wrapper{ margin:0 auto; }

/* 任務23：橫式畫布進入放大檢視時，視覺上轉90度，讓橫式畫布利用手機螢幕較長的那一側。
   純CSS視覺轉向，不動裝置實際方向。做法：.grid-wrapper本身的版面尺寸（寬高）由JS
   直接設成「轉向後」的寬高（即原本的高寬互換），裡面的 #zoomViewport 維持自己原本
   （未轉向）的實際尺寸，用position:absolute置中再transform:rotate(90deg)轉正貼滿
   外層的框。這樣外層.grid-wrapper／再外層.magnify-canvas-slot（overflow:auto）拿到的
   捲動範圍尺寸，本來就是轉向後的正確尺寸，捲動方向不會因為轉向而變得不直覺。 */
.grid-wrapper.rotated{ overflow:visible;max-height:none; }
.grid-wrapper.rotated #zoomViewport{
  position:absolute;
  transform:rotate(90deg);
  /* left/top改由JS算好整數px直接指定（見canvas.js updateGridWrapperSize），
     不用top:50%;left:50%+translate(-50%,-50%)：那個算法碰到奇數px尺寸時
     會產生0.5px的次像素偏移，導致整個轉向後的畫布被瀏覽器做次像素模糊處理，
     視覺上看起來像蒙上一層灰、對比度變低 */
}

/* 畫布縮放範圍調整：完整顯示（不需要捲動）時才出現這個小提示，
   沒出現就代表目前畫布沒有完整顯示，擺放圖案時要注意可能超出可視範圍。
   做成小布標籤的感覺，緊貼畫布外側正邊緣（完全不重疊到畫布本身）。
   桌面版垂吊在畫布下緣（上緣平的像縫在邊上，下緣圓角）；
   手機版鎖定在畫布左側正中間（.badge-side，右緣平的像縫在邊上，左緣圓角）。
   位置用JS依grid-wrapper在同一個定位容器裡的offsetLeft/offsetTop計算（見 positionCanvasFitBadge），
   用position:absolute（不是fixed）是刻意的：這樣捲動頁面時會跟著.canvas-area/.magnify-inner
   的版面一起自然捲動，不用JS監聽scroll事件重新計算，才不會有位置跟不上、視覺上滑動的落差感 */
.canvas-fit-badge{
  display:none;position:absolute;white-space:nowrap;
  background:var(--color-dark-base);color:var(--color-light-text);
  font-size:11px;padding:7px 12px 5px;border-radius:0 0 8px 8px;
  box-shadow:0 3px 6px rgba(0,0,0,.3);
  pointer-events:none;z-index:60;
}
.canvas-fit-badge::before{
  content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);
  width:18px;height:3px;background:rgba(255,255,255,.35);border-radius:0 0 3px 3px;
}
.canvas-fit-badge.badge-side{
  writing-mode:vertical-rl; /* 手機版畫布左邊可用空間很窄，改直式文字才塞得下 */
  transform:translateY(-50%);
  padding:10px 6px;border-radius:8px 0 0 8px;
}
.canvas-fit-badge.badge-side::before{
  top:50%;left:auto;right:0;transform:translateY(-50%);
  width:3px;height:18px;border-radius:3px 0 0 3px;
}
.canvas-fit-badge.show{ display:block; }

/* 任務19方向B使用者回饋：放大檢視新增「單格繪畫」，讓使用者可以直接在空格上畫出單一像素，
   方便細部修整或自行手繪，跟單格去除用同一種底色系統只是換個顏色區分開/關狀態 */
.action-btn.paint-active{
  background:rgba(var(--color-primary-btn-rgb),0.85);color:#fff;border-color:rgba(var(--color-primary-btn-rgb),0.85);
}

/* 任務17：全站彈窗開合＋按鈕按壓的統一微動效，最後在這裡收尾——
   使用者系統設定「減少動態效果」時，把所有淡入/位移/縮放動畫都直接關掉，只保留最終狀態的呈現，
   一次蓋掉所有相關transition/transform，不用一條條回頭加例外 */
@media (prefers-reduced-motion: reduce){
  .help-overlay,.help-card,.magnify-overlay,.magnify-inner,
  .action-btn,.icon-btn,.help-close,.help-nav-btn,.magnify-close,
  .tabs-wrap .tabs-toggle,.tab,.size-orientation-group,#sizeScrim,
  .action-btn svg,#clearBtn svg path,#exportBtn svg path,
  #flipHBtn svg,#flipVBtn svg,#resizeItemBtn svg,#deleteItemBtn svg *,.nudge-pad button svg,
  .receipt-card,.receipt-btn{
    transition:none !important;animation:none !important;
  }
  .help-card,.receipt-card{ transform:none !important; }
  .magnify-inner{ transform:none !important; }
}
