@aiquants/spreadsheet 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
2
- @layer components{.aqsp-root,.aqsp-root *,.aqsp-root :before,.aqsp-root :after{box-sizing:border-box}.aqsp-root{--aqsp-row-header-width:64px;--aqsp-col-header-height:24px;--aqsp-band-row:#0084ff;--aqsp-band-column:#42ff4f;--aqsp-band-intersection:#e1ff00;--aqsp-band-opacity:.2;color:#1f2937;background:#fff;width:100%;height:100%;font-size:13px;line-height:1;position:relative;overflow:hidden}.aqsp-zoom{grid-template-columns:var(--aqsp-row-header-width) minmax(0, 1fr);grid-template-rows:var(--aqsp-col-header-height) minmax(0, 1fr);transform-origin:0 0;width:100%;height:100%;display:grid}.aqsp-corner{background:#f3f4f6;border-bottom:1px solid #d1d5db;border-right:1px solid #d1d5db;grid-area:1/1}.aqsp-col-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-bottom:1px solid #d1d5db;grid-area:1/2;position:relative;overflow:hidden}.aqsp-col-header-scroll{height:100%;position:absolute;top:0;right:0;overflow:hidden}.aqsp-row-header-scroll{width:100%;position:absolute;bottom:0;left:0;overflow:hidden}.aqsp-col-header-track{will-change:transform;position:absolute;inset:0}.aqsp-col-header-cell{white-space:nowrap;color:#4b5563;border-right:1px solid #e5e7eb;justify-content:center;align-items:center;height:100%;display:flex;position:absolute;top:0;overflow:hidden}.aqsp-row-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-right:1px solid #d1d5db;grid-area:2/1;position:relative;overflow:hidden}.aqsp-row-header-track{will-change:transform;position:absolute;top:0;left:0;right:0}.aqsp-row-header-cell{white-space:nowrap;color:#4b5563;font-variant-numeric:tabular-nums;border-bottom:1px solid #e5e7eb;justify-content:flex-end;align-items:center;padding-right:6px;display:flex;position:absolute;left:0;right:0;overflow:hidden}.aqsp-body{position:absolute;inset:0}.aqsp-row{cursor:default}.aqsp-cell{white-space:nowrap;background:#fff;border-bottom:1px solid #e5e7eb;border-right:1px solid #e5e7eb;align-items:center;padding:0 4px;display:flex}.aqsp-cell[data-aqsp-valign=top]{align-items:flex-start}.aqsp-cell[data-aqsp-valign=bottom]{align-items:flex-end}.aqsp-cell[data-aqsp-wrap]{white-space:pre-wrap;overflow-wrap:anywhere}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after{content:"";pointer-events:none;border:5px solid #4b5563;border-color:#4b5563 #4b5563 #0000 #0000;width:0;height:0;position:absolute;top:0;right:0}.aqsp-cell[data-aqsp-comment]:after{border-top-color:#f97316;border-right-color:#f97316}.aqsp-cell[data-aqsp-invalid]:before{content:"";pointer-events:none;border:5px solid #0000;border-color:#0000 #0000 #dc2626 #dc2626;width:0;height:0;position:absolute;bottom:0;left:0}.aqsp-cell[data-aqsp-link]{color:#1d4ed8;text-decoration:underline}.aqsp-body-stack{grid-area:2/2;position:relative}.aqsp-overlay{pointer-events:none;position:absolute;inset:0;overflow:hidden}.aqsp-overlay-quad{pointer-events:none;position:absolute;overflow:hidden}.aqsp-selection-fill{mix-blend-mode:multiply;background:#3b82f62e;border:1px solid #2563ebd9;position:absolute;top:0;left:0}.aqsp-active-frame{box-sizing:border-box;border:2px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect{background:#3b82f61a;border:1px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect[data-aqsp-drag-mode=subtract]{background:#dc262614;border:1px dashed #dc2626}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:#16a34a14;border:1px dashed #16a34a}.aqsp-band{opacity:var(--aqsp-band-opacity);pointer-events:none;position:absolute;top:0;left:0}.aqsp-band[data-aqsp-band=row]{background:var(--aqsp-band-row)}.aqsp-band[data-aqsp-band=column]{background:var(--aqsp-band-column)}.aqsp-band[data-aqsp-band=intersection]{background:var(--aqsp-band-intersection)}.aqsp-clip-marquee{position:absolute;top:0;left:0}.aqsp-clip-marquee:after{content:"";top:var(--aqsp-clip-outset-top,-3px);right:var(--aqsp-clip-outset-right,-3px);bottom:var(--aqsp-clip-outset-bottom,-3px);left:var(--aqsp-clip-outset-left,-3px);background-image:linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(#fff 50%,#2563eb 50%),linear-gradient(#fff 50%,#2563eb 50%);background-position:0 0,8px 100%,0 8px,100% 0;background-repeat:repeat-x,repeat-x,repeat-y,repeat-y;background-size:8px 2px,8px 2px,2px 8px,2px 8px;animation:.4s linear infinite aqsp-marching-ants;position:absolute}@keyframes aqsp-marching-ants{to{background-position:8px 0,0 100%,0 0,100% 8px}}@media (prefers-reduced-motion:reduce){.aqsp-clip-marquee:after{animation:none}}.aqsp-col-resize-strip{cursor:col-resize;height:100%;position:absolute;top:0}.aqsp-row-resize-strip{cursor:row-resize;position:absolute;left:0;right:0}.aqsp-col-header .aqsp-unhide-marker{cursor:col-resize;opacity:.7;background:repeating-linear-gradient(90deg,#2563eb 0 1px,#0000 1px 3px);height:100%;position:absolute;top:0}.aqsp-row-header .aqsp-unhide-marker{cursor:row-resize;opacity:.7;background:repeating-linear-gradient(#2563eb 0 1px,#0000 1px 3px);position:absolute;left:0;right:0}.aqsp-resize-guide{pointer-events:none;background:#2563eb;position:absolute;top:0;left:0}.aqsp-autofill-handle{box-sizing:content-box;pointer-events:auto;cursor:crosshair;background:#2563eb;border:1px solid #fff;width:6px;height:6px;position:absolute;top:0;left:0}.aqsp-autofill-preview{border:1px dashed #16a34a;position:absolute;top:0;left:0}@media (forced-colors:active){.aqsp-band{outline-offset:-2px;background:0 0;outline:2px solid highlight}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after,.aqsp-cell[data-aqsp-invalid]:before{border:1px solid canvastext;width:6px;height:6px}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:0 0;border-color:highlight}.aqsp-selection-fill{outline-offset:-2px;background:0 0;border:none;outline:2px solid highlight}.aqsp-clip-marquee:after{background-image:none;border:2px dashed highlight;animation:none}}.aqsp-col-header-cell[data-aqsp-in-selection],.aqsp-row-header-cell[data-aqsp-in-selection]{color:#1d4ed8;background:#dbeafe;font-weight:600}.aqsp-live-region{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqsp-sink{opacity:0;resize:none;pointer-events:auto;cursor:default;border:0;width:1px;height:1px;padding:0;position:absolute}.aqsp-sink[data-aqsp-editing]{opacity:1;z-index:1;box-sizing:border-box;color:#1f2937;caret-color:#1f2937;white-space:pre;outline-offset:-2px;cursor:text;background:#fff;outline:2px solid #2563eb;padding:0 4px;font-family:inherit;font-size:13px;line-height:1;overflow:hidden}.aqsp-sink[data-aqsp-pointing]{caret-color:#16a34a}.aqsp-popover-layer{pointer-events:none;position:absolute;inset:0;overflow:visible}.aqsp-popover-anchor{pointer-events:none;position:absolute;top:0;left:0}.aqsp-popover-anchor[inert]{visibility:hidden}.aqsp-popover{color:#1f2937;text-align:start;white-space:normal;cursor:default;pointer-events:auto;background:#fff;border:1px solid #d1d5db;border-radius:8px;flex-direction:column;width:320px;max-width:320px;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Noto Sans JP,sans-serif;font-size:13px;line-height:1.4;display:flex;position:absolute;overflow:hidden;box-shadow:0 1px 2px #00000014,0 8px 24px #00000024}.aqsp-popover:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover[data-aqsp-popover-frame=note-tip]{background:#fffbeb;border-color:#f59e0b;box-shadow:0 2px 8px #0000001f}.aqsp-popover-note,.aqsp-popover-comment,.aqsp-popover-link,.aqsp-popover-message{flex-direction:column;min-height:0;padding:10px 12px;display:flex}.aqsp-popover-list{flex-direction:column;min-height:0;padding:6px;display:flex}.aqsp-popover-note-tip{overscroll-behavior:contain;white-space:pre-wrap;overflow-wrap:anywhere;min-height:0;padding:8px 10px;overflow-y:auto}[data-aqsp-popover][data-aqsp-popover-rejected]{border-inline-start:3px solid #dc2626;padding-inline-start:9px}.aqsp-popover-title{color:#374151;align-items:baseline;gap:6px;margin:0 0 6px;font-size:12px;font-weight:600;display:flex}.aqsp-popover-count{color:#6b7280;font-weight:400}.aqsp-popover-textarea,.aqsp-popover-input{width:100%;color:inherit;font:inherit;background:#fff;border:1px solid #d1d5db;border-radius:6px;margin:0;padding:5px 8px;line-height:1.4;display:block}.aqsp-popover-textarea{resize:none;white-space:pre-wrap;flex:auto;height:104px;min-height:56px;overflow:auto}.aqsp-popover-comment .aqsp-popover-textarea{flex:none;height:64px}.aqsp-popover-input{flex:none;height:28px}.aqsp-popover-textarea:focus-visible,.aqsp-popover-input:focus-visible{outline-offset:-1px;border-color:#2563eb;outline:2px solid #2563eb}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-color:#dc2626}.aqsp-popover-textarea[aria-invalid=true]:focus-visible,.aqsp-popover-input[aria-invalid=true]:focus-visible{border-color:#dc2626;outline-color:#dc2626}.aqsp-popover-hint{color:#6b7280;margin:4px 0 0;font-size:12px}[data-aqsp-popover-rejected] .aqsp-popover-hint{color:#b91c1c}.aqsp-popover-field{flex-direction:column;flex:none;gap:3px;margin:0 0 8px;display:flex}.aqsp-popover-field-label{color:#6b7280;font-size:12px}.aqsp-popover-actions{flex:none;align-items:center;gap:6px;margin-top:8px;display:flex}.aqsp-popover-button{color:#1f2937;min-width:56px;height:26px;font:inherit;cursor:pointer;background:#f9fafb;border:1px solid #d1d5db;border-radius:6px;justify-content:center;align-items:center;margin:0;padding:0 10px;font-size:12px;font-weight:500;line-height:1;display:inline-flex}.aqsp-popover-button:not(:disabled):hover{background:#f3f4f6;border-color:#9ca3af}.aqsp-popover-button:focus-visible{outline-offset:1px;outline:2px solid #2563eb}.aqsp-popover-button:disabled{opacity:.5;cursor:not-allowed}.aqsp-popover-button[data-aqsp-popover-save],.aqsp-popover-button[data-aqsp-popover-post]{color:#fff;background:#2563eb;border-color:#2563eb}.aqsp-popover-button[data-aqsp-popover-save]:not(:disabled):hover,.aqsp-popover-button[data-aqsp-popover-post]:not(:disabled):hover{background:#1d4ed8;border-color:#1d4ed8}.aqsp-popover-button[data-aqsp-popover-close]{color:#6b7280;background:0 0;border-color:#0000;width:26px;min-width:0;margin-inline-start:auto;padding:0;font-size:16px;font-weight:400}.aqsp-popover-button[data-aqsp-popover-close]:not(:disabled):hover{color:#1f2937;background:#f3f4f6;border-color:#0000}.aqsp-popover-thread{overscroll-behavior:contain;flex:auto;min-height:48px;max-height:220px;margin:0 0 8px;padding:0;list-style:none;overflow-y:auto}.aqsp-popover-comment-item{border-top:1px solid #f3f4f6;padding:6px 0}.aqsp-popover-comment-item:first-child{border-top:0;padding-top:0}.aqsp-popover-comment-author{color:#111827;font-size:12px;font-weight:600}.aqsp-popover-comment-time{color:#6b7280;font-variant-numeric:tabular-nums;margin-inline-start:6px;font-size:11px}.aqsp-popover-comment-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:2px 0 0}.aqsp-popover-list .aqsp-popover-input{margin-bottom:4px}.aqsp-popover-options{overscroll-behavior:contain;flex:auto;min-height:0;max-height:240px;overflow-y:auto}.aqsp-popover-option{white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:4px;padding:5px 8px;overflow:hidden}.aqsp-popover-option:hover{background:#f3f4f6}.aqsp-popover-option[aria-selected=true]{color:#1e3a8a;background:#dbeafe}.aqsp-popover-option:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover-empty{color:#6b7280;padding:6px 8px;font-size:12px}.aqsp-popover-message{padding-inline-end:40px;position:relative}.aqsp-popover-message .aqsp-popover-title{margin-bottom:2px}.aqsp-popover-message-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.aqsp-popover-message .aqsp-popover-button[data-aqsp-popover-close]{position:absolute;inset-block-start:6px;inset-inline-end:6px}.aqsp-popover-message[data-aqsp-popover-rejected]{background:#fef2f2}.aqsp-popover-message[data-aqsp-popover-rejected] .aqsp-popover-title{color:#b91c1c}@media (forced-colors:active){.aqsp-popover-option:hover,.aqsp-popover-option[aria-selected=true]{outline-offset:-2px;outline:2px solid highlight}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-style:dashed}.aqsp-popover-button[data-aqsp-popover-close]{border-color:buttontext}}[data-aqsp-empty]{width:100%;height:100%;display:block}}
2
+ @layer components{.aqsp-root,.aqsp-root *,.aqsp-root :before,.aqsp-root :after{box-sizing:border-box}.aqsp-root{--aqsp-row-header-width:64px;--aqsp-col-header-height:24px;--aqsp-band-row:#0084ff;--aqsp-band-column:#42ff4f;--aqsp-band-intersection:#e1ff00;--aqsp-band-opacity:.2;color:#1f2937;background:#fff;width:100%;height:100%;font-size:13px;line-height:1;position:relative;overflow:hidden}.aqsp-zoom{grid-template-columns:var(--aqsp-row-header-width) minmax(0, 1fr);grid-template-rows:var(--aqsp-col-header-height) minmax(0, 1fr);transform-origin:0 0;width:100%;height:100%;display:grid}.aqsp-corner{background:#f3f4f6;border-bottom:1px solid #d1d5db;border-right:1px solid #d1d5db;grid-area:1/1}.aqsp-col-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-bottom:1px solid #d1d5db;grid-area:1/2;position:relative;overflow:hidden}.aqsp-col-header-scroll{height:100%;position:absolute;top:0;right:0;overflow:hidden}.aqsp-row-header-scroll{width:100%;position:absolute;bottom:0;left:0;overflow:hidden}.aqsp-col-header-track{will-change:transform;position:absolute;inset:0}.aqsp-col-header-cell{white-space:nowrap;color:#4b5563;border-right:1px solid #e5e7eb;justify-content:center;align-items:center;height:100%;display:flex;position:absolute;top:0;overflow:hidden}.aqsp-row-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-right:1px solid #d1d5db;grid-area:2/1;position:relative;overflow:hidden}.aqsp-row-header-track{will-change:transform;position:absolute;top:0;left:0;right:0}.aqsp-row-header-cell{white-space:nowrap;color:#4b5563;font-variant-numeric:tabular-nums;border-bottom:1px solid #e5e7eb;justify-content:flex-end;align-items:center;padding-right:6px;display:flex;position:absolute;left:0;right:0;overflow:hidden}.aqsp-body{position:absolute;inset:0}.aqsp-row{cursor:default}.aqsp-cell{white-space:nowrap;background:#fff;border-bottom:1px solid #e5e7eb;border-right:1px solid #e5e7eb;align-items:center;padding:0 4px;display:flex}.aqsp-cell[data-aqsp-valign=top]{align-items:flex-start}.aqsp-cell[data-aqsp-valign=bottom]{align-items:flex-end}.aqsp-cell[data-aqsp-wrap]{white-space:pre-wrap;overflow-wrap:anywhere}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after{content:"";pointer-events:none;border:5px solid #4b5563;border-color:#4b5563 #4b5563 #0000 #0000;width:0;height:0;position:absolute;top:0;right:0}.aqsp-cell[data-aqsp-comment]:after{border-top-color:#f97316;border-right-color:#f97316}.aqsp-cell[data-aqsp-invalid]:before{content:"";pointer-events:none;border:5px solid #0000;border-color:#0000 #0000 #dc2626 #dc2626;width:0;height:0;position:absolute;bottom:0;left:0}.aqsp-cell[data-aqsp-link]{color:#1d4ed8;text-decoration:underline}.aqsp-body-stack{grid-area:2/2;position:relative}.aqsp-overlay{pointer-events:none;position:absolute;inset:0;overflow:hidden}.aqsp-overlay-quad{pointer-events:none;position:absolute;overflow:hidden}.aqsp-selection-fill{mix-blend-mode:multiply;background:#3b82f62e;border:1px solid #2563ebd9;position:absolute;top:0;left:0}.aqsp-active-frame{box-sizing:border-box;border:2px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect{background:#3b82f61a;border:1px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect[data-aqsp-drag-mode=subtract]{background:#dc262614;border:1px dashed #dc2626}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:#16a34a14;border:1px dashed #16a34a}.aqsp-band{opacity:var(--aqsp-band-opacity);pointer-events:none;position:absolute;top:0;left:0}.aqsp-band[data-aqsp-band=row]{background:var(--aqsp-band-row)}.aqsp-band[data-aqsp-band=column]{background:var(--aqsp-band-column)}.aqsp-band[data-aqsp-band=intersection]{background:var(--aqsp-band-intersection)}.aqsp-clip-marquee{position:absolute;top:0;left:0}.aqsp-clip-marquee:after{content:"";top:var(--aqsp-clip-outset-top,-3px);right:var(--aqsp-clip-outset-right,-3px);bottom:var(--aqsp-clip-outset-bottom,-3px);left:var(--aqsp-clip-outset-left,-3px);background-image:linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(#fff 50%,#2563eb 50%),linear-gradient(#fff 50%,#2563eb 50%);background-position:0 0,8px 100%,0 8px,100% 0;background-repeat:repeat-x,repeat-x,repeat-y,repeat-y;background-size:8px 2px,8px 2px,2px 8px,2px 8px;animation:.4s linear infinite aqsp-marching-ants;position:absolute}@keyframes aqsp-marching-ants{to{background-position:8px 0,0 100%,0 0,100% 8px}}@media (prefers-reduced-motion:reduce){.aqsp-clip-marquee:after{animation:none}}.aqsp-col-resize-strip{cursor:col-resize;height:100%;position:absolute;top:0}.aqsp-row-resize-strip{cursor:row-resize;position:absolute;left:0;right:0}.aqsp-col-header .aqsp-unhide-marker{cursor:col-resize;opacity:.7;background:repeating-linear-gradient(90deg,#2563eb 0 1px,#0000 1px 3px);height:100%;position:absolute;top:0}.aqsp-row-header .aqsp-unhide-marker{cursor:row-resize;opacity:.7;background:repeating-linear-gradient(#2563eb 0 1px,#0000 1px 3px);position:absolute;left:0;right:0}.aqsp-resize-guide{pointer-events:none;background:#2563eb;position:absolute;top:0;left:0}.aqsp-autofill-handle{box-sizing:content-box;pointer-events:auto;cursor:crosshair;background:#2563eb;border:1px solid #fff;width:6px;height:6px;position:absolute;top:0;left:0}.aqsp-autofill-preview{border:1px dashed #16a34a;position:absolute;top:0;left:0}@media (forced-colors:active){.aqsp-band{outline-offset:-2px;background:0 0;outline:2px solid highlight}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after,.aqsp-cell[data-aqsp-invalid]:before{border:1px solid canvastext;width:6px;height:6px}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:0 0;border-color:highlight}.aqsp-selection-fill{outline-offset:-2px;background:0 0;border:none;outline:2px solid highlight}.aqsp-clip-marquee:after{background-image:none;border:2px dashed highlight;animation:none}}.aqsp-col-header-cell[data-aqsp-in-selection],.aqsp-row-header-cell[data-aqsp-in-selection]{color:#1d4ed8;background:#dbeafe;font-weight:600}.aqsp-live-region{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqsp-sink{opacity:0;resize:none;pointer-events:auto;cursor:default;border:0;width:1px;height:1px;padding:0;position:absolute}.aqsp-sink[data-aqsp-editing]{opacity:1;z-index:1;box-sizing:border-box;color:#1f2937;caret-color:#1f2937;white-space:pre;outline-offset:-2px;cursor:text;background:#fff;outline:2px solid #2563eb;padding:0 4px;font-family:inherit;font-size:13px;line-height:1;overflow:hidden}.aqsp-sink[data-aqsp-pointing]{caret-color:#16a34a}.aqsp-popover-layer{pointer-events:none;position:absolute;inset:0;overflow:visible}.aqsp-popover-anchor{pointer-events:none;position:absolute;top:0;left:0}.aqsp-popover-anchor[inert]{visibility:hidden}.aqsp-popover{color:#1f2937;text-align:start;white-space:normal;cursor:default;pointer-events:auto;background:#fff;border:1px solid #d1d5db;border-radius:8px;flex-direction:column;width:320px;max-width:320px;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Noto Sans JP,sans-serif;font-size:13px;line-height:1.4;display:flex;position:absolute;overflow:hidden;box-shadow:0 1px 2px #00000014,0 8px 24px #00000024}.aqsp-popover:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover[data-aqsp-popover-frame=note-tip]{background:#fffbeb;border-color:#f59e0b;box-shadow:0 2px 8px #0000001f}.aqsp-popover-note,.aqsp-popover-comment,.aqsp-popover-link,.aqsp-popover-message{flex-direction:column;min-height:0;padding:10px 12px;display:flex}.aqsp-popover-list{flex-direction:column;min-height:0;padding:6px;display:flex}.aqsp-popover-note-tip{overscroll-behavior:contain;white-space:pre-wrap;overflow-wrap:anywhere;min-height:0;padding:8px 10px;overflow-y:auto}[data-aqsp-popover][data-aqsp-popover-rejected]{border-inline-start:3px solid #dc2626;padding-inline-start:9px}.aqsp-popover-title{color:#374151;align-items:baseline;gap:6px;margin:0 0 6px;font-size:12px;font-weight:600;display:flex}.aqsp-popover-count{color:#6b7280;font-weight:400}.aqsp-popover-textarea,.aqsp-popover-input{width:100%;color:inherit;font:inherit;background:#fff;border:1px solid #d1d5db;border-radius:6px;margin:0;padding:5px 8px;line-height:1.4;display:block}.aqsp-popover-textarea{resize:none;white-space:pre-wrap;flex:auto;height:104px;min-height:56px;overflow:auto}.aqsp-popover-comment .aqsp-popover-textarea{flex:none;height:64px}.aqsp-popover-input{flex:none;height:28px}.aqsp-popover-textarea:focus-visible,.aqsp-popover-input:focus-visible{outline-offset:-1px;border-color:#2563eb;outline:2px solid #2563eb}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-color:#dc2626}.aqsp-popover-textarea[aria-invalid=true]:focus-visible,.aqsp-popover-input[aria-invalid=true]:focus-visible{border-color:#dc2626;outline-color:#dc2626}.aqsp-popover-hint{color:#6b7280;margin:4px 0 0;font-size:12px}[data-aqsp-popover-rejected] .aqsp-popover-hint{color:#b91c1c}.aqsp-popover-field{flex-direction:column;flex:none;gap:3px;margin:0 0 8px;display:flex}.aqsp-popover-field-label{color:#6b7280;font-size:12px}.aqsp-popover-actions{flex:none;align-items:center;gap:6px;margin-top:8px;display:flex}.aqsp-popover-button{color:#1f2937;min-width:56px;height:26px;font:inherit;cursor:pointer;background:#f9fafb;border:1px solid #d1d5db;border-radius:6px;justify-content:center;align-items:center;margin:0;padding:0 10px;font-size:12px;font-weight:500;line-height:1;display:inline-flex}.aqsp-popover-button:not(:disabled):hover{background:#f3f4f6;border-color:#9ca3af}.aqsp-popover-button:focus-visible{outline-offset:1px;outline:2px solid #2563eb}.aqsp-popover-button:disabled{opacity:.5;cursor:not-allowed}.aqsp-popover-button[data-aqsp-popover-save],.aqsp-popover-button[data-aqsp-popover-post]{color:#fff;background:#2563eb;border-color:#2563eb}.aqsp-popover-button[data-aqsp-popover-save]:not(:disabled):hover,.aqsp-popover-button[data-aqsp-popover-post]:not(:disabled):hover{background:#1d4ed8;border-color:#1d4ed8}.aqsp-popover-button[data-aqsp-popover-close]{color:#6b7280;background:0 0;border-color:#0000;width:26px;min-width:0;margin-inline-start:auto;padding:0;font-size:16px;font-weight:400}.aqsp-popover-button[data-aqsp-popover-close]:not(:disabled):hover{color:#1f2937;background:#f3f4f6;border-color:#0000}.aqsp-popover-thread{overscroll-behavior:contain;flex:auto;min-height:48px;max-height:220px;margin:0 0 8px;padding:0;list-style:none;overflow-y:auto}.aqsp-popover-comment-item{border-top:1px solid #f3f4f6;padding:6px 0}.aqsp-popover-comment-item:first-child{border-top:0;padding-top:0}.aqsp-popover-comment-author{color:#111827;font-size:12px;font-weight:600}.aqsp-popover-comment-time{color:#6b7280;font-variant-numeric:tabular-nums;margin-inline-start:6px;font-size:11px}.aqsp-popover-comment-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:2px 0 0}.aqsp-popover-list .aqsp-popover-input{margin-bottom:4px}.aqsp-popover-options{overscroll-behavior:contain;flex:auto;min-height:0;max-height:240px;overflow-y:auto}.aqsp-popover-option{white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:4px;padding:5px 8px;overflow:hidden}.aqsp-popover-option:hover{background:#f3f4f6}.aqsp-popover-option[aria-selected=true]{color:#1e3a8a;background:#dbeafe}.aqsp-popover-option:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover-empty{color:#6b7280;padding:6px 8px;font-size:12px}.aqsp-popover-message{padding-inline-end:40px;position:relative}.aqsp-popover-message .aqsp-popover-title{margin-bottom:2px}.aqsp-popover-message-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.aqsp-popover-message .aqsp-popover-button[data-aqsp-popover-close]{position:absolute;inset-block-start:6px;inset-inline-end:6px}.aqsp-popover-message[data-aqsp-popover-rejected]{background:#fef2f2}.aqsp-popover-message[data-aqsp-popover-rejected] .aqsp-popover-title{color:#b91c1c}@media (forced-colors:active){.aqsp-popover-option:hover,.aqsp-popover-option[aria-selected=true]{outline-offset:-2px;outline:2px solid highlight}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-style:dashed}.aqsp-popover-button[data-aqsp-popover-close]{border-color:buttontext}}[data-aqsp-empty]{width:100%;height:100%;display:block}.aqsp-freeze-divider{background:var(--aqsp-divider-color,#9ca3af);pointer-events:none;position:absolute}.aqsp-freeze-divider-v{width:var(--aqsp-divider-width,2px)}.aqsp-freeze-divider-h{height:var(--aqsp-divider-width,2px)}@media (forced-colors:active){.aqsp-freeze-divider{background:canvastext}}}
@@ -1,3 +1,3 @@
1
1
  /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
2
2
  /*! @aiquants/spreadsheet standalone CSS — 非 Tailwind ホスト専用。ホストの Tailwind ビルドと混在させないこと */
3
- @layer theme,base;@layer components{@layer components{.aqvs-scroll-pane{display:flex;position:relative}.aqvs-scroll-pane[data-self-measured=true]{height:100%}.aqvs-scroll-pane-content{box-sizing:border-box;flex:1;height:100%;position:relative;overflow:hidden}.aqvs-tap-scroll-circle{touch-action:none;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;transition-property:transform;transition-duration:.1s;transition-timing-function:cubic-bezier(0,0,.2,1);display:flex;position:relative}.aqvs-tap-scroll-circle-visual-outer{border-radius:9999px;position:absolute;inset:0}.aqvs-tap-scroll-circle-gradient{background:linear-gradient(to bottom right,#1d4ed899,#60a5fa8c,#bfdbfe66);border:1px solid #fff6;border-radius:9999px;position:absolute;inset:0;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.aqvs-tap-scroll-circle-inner{border-radius:9999px;position:absolute;inset:18%}.aqvs-sample-visual-pupil{box-sizing:border-box;background-color:#ffffffd9;border:1px solid #ffffff80;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-sample-visual-highlight{background-color:#fffc;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-sample-visual-rod{background-color:#ffffff80;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-scrollbar{z-index:50;cursor:default;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:none;background-color:#fff;position:relative}.aqvs-scrollbar-horizontal{flex-direction:row;align-items:stretch;display:flex}.aqvs-scrollbar-vertical{flex-direction:column;align-items:stretch;display:flex}.aqvs-scrollbar[data-visible=false],.aqvs-scrollbar-thumb-wrapper[data-visible=false]{opacity:0;pointer-events:none}.aqvs-scrollbar-tap-circle-wrapper{pointer-events:auto;transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);position:absolute}.aqvs-scrollbar-arrow-button{color:#313131;letter-spacing:normal;background-color:#e0e0e0;border:0 solid;justify-content:center;align-items:center;padding:0;font-family:system-ui,sans-serif;font-size:.75rem;font-weight:400;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);display:flex}.aqvs-scrollbar-arrow-button:focus{outline-offset:2px;outline:2px solid #0000}.aqvs-scrollbar-arrow-button:focus-visible{outline-offset:1px;outline:2px solid #60a5fa}.aqvs-scrollbar-arrow-button:disabled{cursor:not-allowed;opacity:.5}.aqvs-scrollbar-arrow-button:enabled:hover{background-color:#d4d4d4}.aqvs-scrollbar-track{background-color:#f5f5f5;flex:1;position:relative}.aqvs-scrollbar-overlay{pointer-events:none;position:absolute;inset:0}.aqvs-scrollbar-thumb-wrapper{touch-action:none;position:absolute}.aqvs-scrollbar-thumb{transform-origin:50%;background-color:#7f7f7f;transition:transform 80ms ease-out;position:absolute}.aqvs-scrollbar-thumb[data-thumb-state=disabled]{transition:none;transform:none}.aqvs-scrollbar-thumb[data-thumb-state=hover]{background-color:#5f5f5f}.aqvs-scrollbar-thumb[data-thumb-state=dragging]{background-color:#4f4f4f;transition:transform 60ms ease-out}.aqvs-scrollbar-thumb-horizontal{inset:1.5px 0}.aqvs-scrollbar-thumb-horizontal[data-thumb-state=hover]{top:-.5px;bottom:-.5px;transform:scaleY(1.06)}.aqvs-scrollbar-thumb-horizontal[data-thumb-state=dragging]{top:-.5px;bottom:-.5px;transform:scaleY(1.12)}.aqvs-scrollbar-thumb-vertical{inset:0 1.5px}.aqvs-scrollbar-thumb-vertical[data-thumb-state=hover]{left:-.5px;right:-.5px;transform:scaleX(1.06)}.aqvs-scrollbar-thumb-vertical[data-thumb-state=dragging]{left:-.5px;right:-.5px;transform:scaleX(1.12)}.aqvs-scroll-to-edge-button{pointer-events:auto;cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;color:#fff;text-transform:uppercase;letter-spacing:.05em;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background-color:#1f2937cc;border:0 solid;border-radius:9999px;padding:.25rem 3rem;font-family:inherit;font-size:10px;font-weight:500;line-height:1.5;transition-property:transform,background-color;transition-duration:.15s;transform:none;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.aqvs-scroll-to-edge-button:focus{outline-offset:2px;outline:2px solid #0000}.aqvs-scroll-to-edge-button:focus-visible{outline-offset:1px;outline:2px solid #60a5fa}.aqvs-scroll-to-edge-button:hover{background-color:#374151}.aqvs-scroll-to-edge-button:active{transform:scale(.95)}.aqvs-scroll-to-edge-overlay{pointer-events:none;z-index:10;transition-property:opacity;transition-duration:.5s;position:absolute;inset:0}.aqvs-scroll-to-edge-overlay[data-visible=true]{opacity:1}.aqvs-scroll-to-edge-overlay[data-visible=false]{opacity:0}.aqvs-scroll-to-edge-overlay[data-visible=false] .aqvs-scroll-to-edge-button{pointer-events:none}.aqvs-scroll-to-edge-button-container{justify-content:center;display:flex;position:absolute;left:0;right:0}.aqvs-scroll-to-edge-button-container-top{top:.5rem}.aqvs-scroll-to-edge-button-container-bottom{bottom:.5rem}.aqvs-no-items-container{width:100%;position:absolute;top:0}.aqvs-no-items-text{text-align:center;color:#6b7280}.aqvs-item-container,.aqvs-bottom-inset,.aqvs-items-wrapper{width:100%;position:absolute}.aqvs-live-region{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqvs-grid{grid-template-rows:minmax(0,1fr) auto;width:100%;height:100%;display:grid;position:relative;overflow:hidden}.aqvs-grid-has-frozen-rows{grid-template-rows:auto minmax(0,1fr) auto}.aqvs-grid-frozen-rows{min-width:0;position:relative;overflow:hidden}.aqvs-grid-frozen-band-row{position:absolute;left:0;overflow:hidden}.aqvs-grid-main{min-width:0;min-height:0;position:relative}.aqvs-grid-row{width:100%;height:100%;transform:translateX(var(--aqvs-grid-hx-residual,0px));position:relative;overflow:visible}.aqvs-grid-cell{height:100%;position:absolute;top:0;overflow:hidden}.aqvs-grid-row.aqvs-grid-row-frozen-host{transform:none}.aqvs-grid-row-scroll{height:100%;top:0;left:var(--aqvs-grid-frozen-width,0px);position:absolute;right:0;overflow:hidden}.aqvs-grid-row-scroll-inner{width:100%;height:100%;transform:translateX(calc(var(--aqvs-grid-hx-residual,0px) - var(--aqvs-grid-frozen-width,0px)));position:absolute;top:0;left:0}.aqvs-grid-hbar-strip{min-width:0;padding-left:var(--aqvs-grid-frozen-width,0px);position:relative}.aqvs-grid-live-region{clip:rect(0 0 0 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}}.aqsp-root,.aqsp-root *,.aqsp-root :before,.aqsp-root :after{box-sizing:border-box}.aqsp-root{--aqsp-row-header-width:64px;--aqsp-col-header-height:24px;--aqsp-band-row:#0084ff;--aqsp-band-column:#42ff4f;--aqsp-band-intersection:#e1ff00;--aqsp-band-opacity:.2;color:#1f2937;background:#fff;width:100%;height:100%;font-size:13px;line-height:1;position:relative;overflow:hidden}.aqsp-zoom{grid-template-columns:var(--aqsp-row-header-width) minmax(0, 1fr);grid-template-rows:var(--aqsp-col-header-height) minmax(0, 1fr);transform-origin:0 0;width:100%;height:100%;display:grid}.aqsp-corner{background:#f3f4f6;border-bottom:1px solid #d1d5db;border-right:1px solid #d1d5db;grid-area:1/1}.aqsp-col-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-bottom:1px solid #d1d5db;grid-area:1/2;position:relative;overflow:hidden}.aqsp-col-header-scroll{height:100%;position:absolute;top:0;right:0;overflow:hidden}.aqsp-row-header-scroll{width:100%;position:absolute;bottom:0;left:0;overflow:hidden}.aqsp-col-header-track{will-change:transform;position:absolute;inset:0}.aqsp-col-header-cell{white-space:nowrap;color:#4b5563;border-right:1px solid #e5e7eb;justify-content:center;align-items:center;height:100%;display:flex;position:absolute;top:0;overflow:hidden}.aqsp-row-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-right:1px solid #d1d5db;grid-area:2/1;position:relative;overflow:hidden}.aqsp-row-header-track{will-change:transform;position:absolute;top:0;left:0;right:0}.aqsp-row-header-cell{white-space:nowrap;color:#4b5563;font-variant-numeric:tabular-nums;border-bottom:1px solid #e5e7eb;justify-content:flex-end;align-items:center;padding-right:6px;display:flex;position:absolute;left:0;right:0;overflow:hidden}.aqsp-body{position:absolute;inset:0}.aqsp-row{cursor:default}.aqsp-cell{white-space:nowrap;background:#fff;border-bottom:1px solid #e5e7eb;border-right:1px solid #e5e7eb;align-items:center;padding:0 4px;display:flex}.aqsp-cell[data-aqsp-valign=top]{align-items:flex-start}.aqsp-cell[data-aqsp-valign=bottom]{align-items:flex-end}.aqsp-cell[data-aqsp-wrap]{white-space:pre-wrap;overflow-wrap:anywhere}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after{content:"";pointer-events:none;border:5px solid #4b5563;border-color:#4b5563 #4b5563 #0000 #0000;width:0;height:0;position:absolute;top:0;right:0}.aqsp-cell[data-aqsp-comment]:after{border-top-color:#f97316;border-right-color:#f97316}.aqsp-cell[data-aqsp-invalid]:before{content:"";pointer-events:none;border:5px solid #0000;border-color:#0000 #0000 #dc2626 #dc2626;width:0;height:0;position:absolute;bottom:0;left:0}.aqsp-cell[data-aqsp-link]{color:#1d4ed8;text-decoration:underline}.aqsp-body-stack{grid-area:2/2;position:relative}.aqsp-overlay{pointer-events:none;position:absolute;inset:0;overflow:hidden}.aqsp-overlay-quad{pointer-events:none;position:absolute;overflow:hidden}.aqsp-selection-fill{mix-blend-mode:multiply;background:#3b82f62e;border:1px solid #2563ebd9;position:absolute;top:0;left:0}.aqsp-active-frame{box-sizing:border-box;border:2px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect{background:#3b82f61a;border:1px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect[data-aqsp-drag-mode=subtract]{background:#dc262614;border:1px dashed #dc2626}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:#16a34a14;border:1px dashed #16a34a}.aqsp-band{opacity:var(--aqsp-band-opacity);pointer-events:none;position:absolute;top:0;left:0}.aqsp-band[data-aqsp-band=row]{background:var(--aqsp-band-row)}.aqsp-band[data-aqsp-band=column]{background:var(--aqsp-band-column)}.aqsp-band[data-aqsp-band=intersection]{background:var(--aqsp-band-intersection)}.aqsp-clip-marquee{position:absolute;top:0;left:0}.aqsp-clip-marquee:after{content:"";top:var(--aqsp-clip-outset-top,-3px);right:var(--aqsp-clip-outset-right,-3px);bottom:var(--aqsp-clip-outset-bottom,-3px);left:var(--aqsp-clip-outset-left,-3px);background-image:linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(#fff 50%,#2563eb 50%),linear-gradient(#fff 50%,#2563eb 50%);background-position:0 0,8px 100%,0 8px,100% 0;background-repeat:repeat-x,repeat-x,repeat-y,repeat-y;background-size:8px 2px,8px 2px,2px 8px,2px 8px;animation:.4s linear infinite aqsp-marching-ants;position:absolute}@keyframes aqsp-marching-ants{to{background-position:8px 0,0 100%,0 0,100% 8px}}@media (prefers-reduced-motion:reduce){.aqsp-clip-marquee:after{animation:none}}.aqsp-col-resize-strip{cursor:col-resize;height:100%;position:absolute;top:0}.aqsp-row-resize-strip{cursor:row-resize;position:absolute;left:0;right:0}.aqsp-col-header .aqsp-unhide-marker{cursor:col-resize;opacity:.7;background:repeating-linear-gradient(90deg,#2563eb 0 1px,#0000 1px 3px);height:100%;position:absolute;top:0}.aqsp-row-header .aqsp-unhide-marker{cursor:row-resize;opacity:.7;background:repeating-linear-gradient(#2563eb 0 1px,#0000 1px 3px);position:absolute;left:0;right:0}.aqsp-resize-guide{pointer-events:none;background:#2563eb;position:absolute;top:0;left:0}.aqsp-autofill-handle{box-sizing:content-box;pointer-events:auto;cursor:crosshair;background:#2563eb;border:1px solid #fff;width:6px;height:6px;position:absolute;top:0;left:0}.aqsp-autofill-preview{border:1px dashed #16a34a;position:absolute;top:0;left:0}@media (forced-colors:active){.aqsp-band{outline-offset:-2px;background:0 0;outline:2px solid highlight}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after,.aqsp-cell[data-aqsp-invalid]:before{border:1px solid canvastext;width:6px;height:6px}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:0 0;border-color:highlight}.aqsp-selection-fill{outline-offset:-2px;background:0 0;border:none;outline:2px solid highlight}.aqsp-clip-marquee:after{background-image:none;border:2px dashed highlight;animation:none}}.aqsp-col-header-cell[data-aqsp-in-selection],.aqsp-row-header-cell[data-aqsp-in-selection]{color:#1d4ed8;background:#dbeafe;font-weight:600}.aqsp-live-region{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqsp-sink{opacity:0;resize:none;pointer-events:auto;cursor:default;border:0;width:1px;height:1px;padding:0;position:absolute}.aqsp-sink[data-aqsp-editing]{opacity:1;z-index:1;box-sizing:border-box;color:#1f2937;caret-color:#1f2937;white-space:pre;outline-offset:-2px;cursor:text;background:#fff;outline:2px solid #2563eb;padding:0 4px;font-family:inherit;font-size:13px;line-height:1;overflow:hidden}.aqsp-sink[data-aqsp-pointing]{caret-color:#16a34a}.aqsp-popover-layer{pointer-events:none;position:absolute;inset:0;overflow:visible}.aqsp-popover-anchor{pointer-events:none;position:absolute;top:0;left:0}.aqsp-popover-anchor[inert]{visibility:hidden}.aqsp-popover{color:#1f2937;text-align:start;white-space:normal;cursor:default;pointer-events:auto;background:#fff;border:1px solid #d1d5db;border-radius:8px;flex-direction:column;width:320px;max-width:320px;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Noto Sans JP,sans-serif;font-size:13px;line-height:1.4;display:flex;position:absolute;overflow:hidden;box-shadow:0 1px 2px #00000014,0 8px 24px #00000024}.aqsp-popover:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover[data-aqsp-popover-frame=note-tip]{background:#fffbeb;border-color:#f59e0b;box-shadow:0 2px 8px #0000001f}.aqsp-popover-note,.aqsp-popover-comment,.aqsp-popover-link,.aqsp-popover-message{flex-direction:column;min-height:0;padding:10px 12px;display:flex}.aqsp-popover-list{flex-direction:column;min-height:0;padding:6px;display:flex}.aqsp-popover-note-tip{overscroll-behavior:contain;white-space:pre-wrap;overflow-wrap:anywhere;min-height:0;padding:8px 10px;overflow-y:auto}[data-aqsp-popover][data-aqsp-popover-rejected]{border-inline-start:3px solid #dc2626;padding-inline-start:9px}.aqsp-popover-title{color:#374151;align-items:baseline;gap:6px;margin:0 0 6px;font-size:12px;font-weight:600;display:flex}.aqsp-popover-count{color:#6b7280;font-weight:400}.aqsp-popover-textarea,.aqsp-popover-input{width:100%;color:inherit;font:inherit;background:#fff;border:1px solid #d1d5db;border-radius:6px;margin:0;padding:5px 8px;line-height:1.4;display:block}.aqsp-popover-textarea{resize:none;white-space:pre-wrap;flex:auto;height:104px;min-height:56px;overflow:auto}.aqsp-popover-comment .aqsp-popover-textarea{flex:none;height:64px}.aqsp-popover-input{flex:none;height:28px}.aqsp-popover-textarea:focus-visible,.aqsp-popover-input:focus-visible{outline-offset:-1px;border-color:#2563eb;outline:2px solid #2563eb}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-color:#dc2626}.aqsp-popover-textarea[aria-invalid=true]:focus-visible,.aqsp-popover-input[aria-invalid=true]:focus-visible{border-color:#dc2626;outline-color:#dc2626}.aqsp-popover-hint{color:#6b7280;margin:4px 0 0;font-size:12px}[data-aqsp-popover-rejected] .aqsp-popover-hint{color:#b91c1c}.aqsp-popover-field{flex-direction:column;flex:none;gap:3px;margin:0 0 8px;display:flex}.aqsp-popover-field-label{color:#6b7280;font-size:12px}.aqsp-popover-actions{flex:none;align-items:center;gap:6px;margin-top:8px;display:flex}.aqsp-popover-button{color:#1f2937;min-width:56px;height:26px;font:inherit;cursor:pointer;background:#f9fafb;border:1px solid #d1d5db;border-radius:6px;justify-content:center;align-items:center;margin:0;padding:0 10px;font-size:12px;font-weight:500;line-height:1;display:inline-flex}.aqsp-popover-button:not(:disabled):hover{background:#f3f4f6;border-color:#9ca3af}.aqsp-popover-button:focus-visible{outline-offset:1px;outline:2px solid #2563eb}.aqsp-popover-button:disabled{opacity:.5;cursor:not-allowed}.aqsp-popover-button[data-aqsp-popover-save],.aqsp-popover-button[data-aqsp-popover-post]{color:#fff;background:#2563eb;border-color:#2563eb}.aqsp-popover-button[data-aqsp-popover-save]:not(:disabled):hover,.aqsp-popover-button[data-aqsp-popover-post]:not(:disabled):hover{background:#1d4ed8;border-color:#1d4ed8}.aqsp-popover-button[data-aqsp-popover-close]{color:#6b7280;background:0 0;border-color:#0000;width:26px;min-width:0;margin-inline-start:auto;padding:0;font-size:16px;font-weight:400}.aqsp-popover-button[data-aqsp-popover-close]:not(:disabled):hover{color:#1f2937;background:#f3f4f6;border-color:#0000}.aqsp-popover-thread{overscroll-behavior:contain;flex:auto;min-height:48px;max-height:220px;margin:0 0 8px;padding:0;list-style:none;overflow-y:auto}.aqsp-popover-comment-item{border-top:1px solid #f3f4f6;padding:6px 0}.aqsp-popover-comment-item:first-child{border-top:0;padding-top:0}.aqsp-popover-comment-author{color:#111827;font-size:12px;font-weight:600}.aqsp-popover-comment-time{color:#6b7280;font-variant-numeric:tabular-nums;margin-inline-start:6px;font-size:11px}.aqsp-popover-comment-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:2px 0 0}.aqsp-popover-list .aqsp-popover-input{margin-bottom:4px}.aqsp-popover-options{overscroll-behavior:contain;flex:auto;min-height:0;max-height:240px;overflow-y:auto}.aqsp-popover-option{white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:4px;padding:5px 8px;overflow:hidden}.aqsp-popover-option:hover{background:#f3f4f6}.aqsp-popover-option[aria-selected=true]{color:#1e3a8a;background:#dbeafe}.aqsp-popover-option:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover-empty{color:#6b7280;padding:6px 8px;font-size:12px}.aqsp-popover-message{padding-inline-end:40px;position:relative}.aqsp-popover-message .aqsp-popover-title{margin-bottom:2px}.aqsp-popover-message-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.aqsp-popover-message .aqsp-popover-button[data-aqsp-popover-close]{position:absolute;inset-block-start:6px;inset-inline-end:6px}.aqsp-popover-message[data-aqsp-popover-rejected]{background:#fef2f2}.aqsp-popover-message[data-aqsp-popover-rejected] .aqsp-popover-title{color:#b91c1c}@media (forced-colors:active){.aqsp-popover-option:hover,.aqsp-popover-option[aria-selected=true]{outline-offset:-2px;outline:2px solid highlight}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-style:dashed}.aqsp-popover-button[data-aqsp-popover-close]{border-color:buttontext}}[data-aqsp-empty]{width:100%;height:100%;display:block}}@layer utilities;
3
+ @layer theme,base;@layer components{@layer components{.aqvs-scroll-pane{display:flex;position:relative}.aqvs-scroll-pane[data-self-measured=true]{height:100%}.aqvs-scroll-pane-content{box-sizing:border-box;flex:1;height:100%;position:relative;overflow:hidden}.aqvs-tap-scroll-circle{touch-action:none;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;transition-property:transform;transition-duration:.1s;transition-timing-function:cubic-bezier(0,0,.2,1);display:flex;position:relative}.aqvs-tap-scroll-circle-visual-outer{border-radius:9999px;position:absolute;inset:0}.aqvs-tap-scroll-circle-gradient{background:linear-gradient(to bottom right,#1d4ed899,#60a5fa8c,#bfdbfe66);border:1px solid #fff6;border-radius:9999px;position:absolute;inset:0;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.aqvs-tap-scroll-circle-inner{border-radius:9999px;position:absolute;inset:18%}.aqvs-sample-visual-pupil{box-sizing:border-box;background-color:#ffffffd9;border:1px solid #ffffff80;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-sample-visual-highlight{background-color:#fffc;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-sample-visual-rod{background-color:#ffffff80;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-scrollbar{z-index:50;cursor:default;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:none;background-color:#fff;position:relative}.aqvs-scrollbar-horizontal{flex-direction:row;align-items:stretch;display:flex}.aqvs-scrollbar-vertical{flex-direction:column;align-items:stretch;display:flex}.aqvs-scrollbar[data-visible=false],.aqvs-scrollbar-thumb-wrapper[data-visible=false]{opacity:0;pointer-events:none}.aqvs-scrollbar-tap-circle-wrapper{pointer-events:auto;transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);position:absolute}.aqvs-scrollbar-arrow-button{color:#313131;letter-spacing:normal;background-color:#e0e0e0;border:0 solid;justify-content:center;align-items:center;padding:0;font-family:system-ui,sans-serif;font-size:.75rem;font-weight:400;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);display:flex}.aqvs-scrollbar-arrow-button:focus{outline-offset:2px;outline:2px solid #0000}.aqvs-scrollbar-arrow-button:focus-visible{outline-offset:1px;outline:2px solid #60a5fa}.aqvs-scrollbar-arrow-button:disabled{cursor:not-allowed;opacity:.5}.aqvs-scrollbar-arrow-button:enabled:hover{background-color:#d4d4d4}.aqvs-scrollbar-track{background-color:#f5f5f5;flex:1;position:relative}.aqvs-scrollbar-overlay{pointer-events:none;position:absolute;inset:0}.aqvs-scrollbar-thumb-wrapper{touch-action:none;position:absolute}.aqvs-scrollbar-thumb{transform-origin:50%;background-color:#7f7f7f;transition:transform 80ms ease-out;position:absolute}.aqvs-scrollbar-thumb[data-thumb-state=disabled]{transition:none;transform:none}.aqvs-scrollbar-thumb[data-thumb-state=hover]{background-color:#5f5f5f}.aqvs-scrollbar-thumb[data-thumb-state=dragging]{background-color:#4f4f4f;transition:transform 60ms ease-out}.aqvs-scrollbar-thumb-horizontal{inset:1.5px 0}.aqvs-scrollbar-thumb-horizontal[data-thumb-state=hover]{top:-.5px;bottom:-.5px;transform:scaleY(1.06)}.aqvs-scrollbar-thumb-horizontal[data-thumb-state=dragging]{top:-.5px;bottom:-.5px;transform:scaleY(1.12)}.aqvs-scrollbar-thumb-vertical{inset:0 1.5px}.aqvs-scrollbar-thumb-vertical[data-thumb-state=hover]{left:-.5px;right:-.5px;transform:scaleX(1.06)}.aqvs-scrollbar-thumb-vertical[data-thumb-state=dragging]{left:-.5px;right:-.5px;transform:scaleX(1.12)}.aqvs-scroll-to-edge-button{pointer-events:auto;cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;color:#fff;text-transform:uppercase;letter-spacing:.05em;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background-color:#1f2937cc;border:0 solid;border-radius:9999px;padding:.25rem 3rem;font-family:inherit;font-size:10px;font-weight:500;line-height:1.5;transition-property:transform,background-color;transition-duration:.15s;transform:none;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.aqvs-scroll-to-edge-button:focus{outline-offset:2px;outline:2px solid #0000}.aqvs-scroll-to-edge-button:focus-visible{outline-offset:1px;outline:2px solid #60a5fa}.aqvs-scroll-to-edge-button:hover{background-color:#374151}.aqvs-scroll-to-edge-button:active{transform:scale(.95)}.aqvs-scroll-to-edge-overlay{pointer-events:none;z-index:10;transition-property:opacity;transition-duration:.5s;position:absolute;inset:0}.aqvs-scroll-to-edge-overlay[data-visible=true]{opacity:1}.aqvs-scroll-to-edge-overlay[data-visible=false]{opacity:0}.aqvs-scroll-to-edge-overlay[data-visible=false] .aqvs-scroll-to-edge-button{pointer-events:none}.aqvs-scroll-to-edge-button-container{justify-content:center;display:flex;position:absolute;left:0;right:0}.aqvs-scroll-to-edge-button-container-top{top:.5rem}.aqvs-scroll-to-edge-button-container-bottom{bottom:.5rem}.aqvs-no-items-container{width:100%;position:absolute;top:0}.aqvs-no-items-text{text-align:center;color:#6b7280}.aqvs-item-container,.aqvs-bottom-inset,.aqvs-items-wrapper{width:100%;position:absolute}.aqvs-live-region{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqvs-grid{grid-template-rows:minmax(0,1fr) auto;width:100%;height:100%;display:grid;position:relative;overflow:hidden}.aqvs-grid-has-frozen-rows{grid-template-rows:auto minmax(0,1fr) auto}.aqvs-grid-has-trailing-rows{grid-template-rows:minmax(0,1fr) auto auto}.aqvs-grid-has-frozen-rows.aqvs-grid-has-trailing-rows{grid-template-rows:auto minmax(0,1fr) auto auto}.aqvs-grid-frozen-rows{min-width:0;position:relative;overflow:hidden}.aqvs-grid-frozen-band-row{position:absolute;left:0;overflow:hidden}.aqvs-grid-trailing-rows{min-width:0;position:relative;overflow:hidden}.aqvs-grid-trailing-rows-inner{position:absolute;bottom:0;left:0;right:0}.aqvs-grid-trailing-band-row{position:absolute;left:0;overflow:hidden}.aqvs-grid-main{min-width:0;min-height:0;position:relative}.aqvs-grid-row{width:100%;height:100%;transform:translateX(var(--aqvs-grid-hx-residual,0px));position:relative;overflow:visible}.aqvs-grid-cell{height:100%;position:absolute;top:0;overflow:hidden}.aqvs-grid-row.aqvs-grid-row-frozen-host{transform:none}.aqvs-grid-row-scroll{height:100%;top:0;left:var(--aqvs-grid-frozen-width,0px);right:var(--aqvs-grid-trailing-width,0px);position:absolute;overflow:hidden}.aqvs-grid-row-scroll-inner{width:100%;height:100%;transform:translateX(calc(var(--aqvs-grid-hx-residual,0px) - var(--aqvs-grid-frozen-width,0px)));position:absolute;top:0;left:0}.aqvs-grid-row-trailing{height:100%;top:0;left:max(var(--aqvs-grid-frozen-width,0px), calc(100% - var(--aqvs-grid-trailing-width,0px)));position:absolute;right:0;overflow:hidden}.aqvs-grid-row-trailing-inner{height:100%;width:var(--aqvs-grid-trailing-width,0px);position:absolute;top:0;right:0}.aqvs-grid-hbar-strip{min-width:0;padding-left:var(--aqvs-grid-frozen-width,0px);position:relative}.aqvs-grid-live-region{clip:rect(0 0 0 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}}.aqsp-root,.aqsp-root *,.aqsp-root :before,.aqsp-root :after{box-sizing:border-box}.aqsp-root{--aqsp-row-header-width:64px;--aqsp-col-header-height:24px;--aqsp-band-row:#0084ff;--aqsp-band-column:#42ff4f;--aqsp-band-intersection:#e1ff00;--aqsp-band-opacity:.2;color:#1f2937;background:#fff;width:100%;height:100%;font-size:13px;line-height:1;position:relative;overflow:hidden}.aqsp-zoom{grid-template-columns:var(--aqsp-row-header-width) minmax(0, 1fr);grid-template-rows:var(--aqsp-col-header-height) minmax(0, 1fr);transform-origin:0 0;width:100%;height:100%;display:grid}.aqsp-corner{background:#f3f4f6;border-bottom:1px solid #d1d5db;border-right:1px solid #d1d5db;grid-area:1/1}.aqsp-col-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-bottom:1px solid #d1d5db;grid-area:1/2;position:relative;overflow:hidden}.aqsp-col-header-scroll{height:100%;position:absolute;top:0;right:0;overflow:hidden}.aqsp-row-header-scroll{width:100%;position:absolute;bottom:0;left:0;overflow:hidden}.aqsp-col-header-track{will-change:transform;position:absolute;inset:0}.aqsp-col-header-cell{white-space:nowrap;color:#4b5563;border-right:1px solid #e5e7eb;justify-content:center;align-items:center;height:100%;display:flex;position:absolute;top:0;overflow:hidden}.aqsp-row-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-right:1px solid #d1d5db;grid-area:2/1;position:relative;overflow:hidden}.aqsp-row-header-track{will-change:transform;position:absolute;top:0;left:0;right:0}.aqsp-row-header-cell{white-space:nowrap;color:#4b5563;font-variant-numeric:tabular-nums;border-bottom:1px solid #e5e7eb;justify-content:flex-end;align-items:center;padding-right:6px;display:flex;position:absolute;left:0;right:0;overflow:hidden}.aqsp-body{position:absolute;inset:0}.aqsp-row{cursor:default}.aqsp-cell{white-space:nowrap;background:#fff;border-bottom:1px solid #e5e7eb;border-right:1px solid #e5e7eb;align-items:center;padding:0 4px;display:flex}.aqsp-cell[data-aqsp-valign=top]{align-items:flex-start}.aqsp-cell[data-aqsp-valign=bottom]{align-items:flex-end}.aqsp-cell[data-aqsp-wrap]{white-space:pre-wrap;overflow-wrap:anywhere}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after{content:"";pointer-events:none;border:5px solid #4b5563;border-color:#4b5563 #4b5563 #0000 #0000;width:0;height:0;position:absolute;top:0;right:0}.aqsp-cell[data-aqsp-comment]:after{border-top-color:#f97316;border-right-color:#f97316}.aqsp-cell[data-aqsp-invalid]:before{content:"";pointer-events:none;border:5px solid #0000;border-color:#0000 #0000 #dc2626 #dc2626;width:0;height:0;position:absolute;bottom:0;left:0}.aqsp-cell[data-aqsp-link]{color:#1d4ed8;text-decoration:underline}.aqsp-body-stack{grid-area:2/2;position:relative}.aqsp-overlay{pointer-events:none;position:absolute;inset:0;overflow:hidden}.aqsp-overlay-quad{pointer-events:none;position:absolute;overflow:hidden}.aqsp-selection-fill{mix-blend-mode:multiply;background:#3b82f62e;border:1px solid #2563ebd9;position:absolute;top:0;left:0}.aqsp-active-frame{box-sizing:border-box;border:2px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect{background:#3b82f61a;border:1px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect[data-aqsp-drag-mode=subtract]{background:#dc262614;border:1px dashed #dc2626}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:#16a34a14;border:1px dashed #16a34a}.aqsp-band{opacity:var(--aqsp-band-opacity);pointer-events:none;position:absolute;top:0;left:0}.aqsp-band[data-aqsp-band=row]{background:var(--aqsp-band-row)}.aqsp-band[data-aqsp-band=column]{background:var(--aqsp-band-column)}.aqsp-band[data-aqsp-band=intersection]{background:var(--aqsp-band-intersection)}.aqsp-clip-marquee{position:absolute;top:0;left:0}.aqsp-clip-marquee:after{content:"";top:var(--aqsp-clip-outset-top,-3px);right:var(--aqsp-clip-outset-right,-3px);bottom:var(--aqsp-clip-outset-bottom,-3px);left:var(--aqsp-clip-outset-left,-3px);background-image:linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(#fff 50%,#2563eb 50%),linear-gradient(#fff 50%,#2563eb 50%);background-position:0 0,8px 100%,0 8px,100% 0;background-repeat:repeat-x,repeat-x,repeat-y,repeat-y;background-size:8px 2px,8px 2px,2px 8px,2px 8px;animation:.4s linear infinite aqsp-marching-ants;position:absolute}@keyframes aqsp-marching-ants{to{background-position:8px 0,0 100%,0 0,100% 8px}}@media (prefers-reduced-motion:reduce){.aqsp-clip-marquee:after{animation:none}}.aqsp-col-resize-strip{cursor:col-resize;height:100%;position:absolute;top:0}.aqsp-row-resize-strip{cursor:row-resize;position:absolute;left:0;right:0}.aqsp-col-header .aqsp-unhide-marker{cursor:col-resize;opacity:.7;background:repeating-linear-gradient(90deg,#2563eb 0 1px,#0000 1px 3px);height:100%;position:absolute;top:0}.aqsp-row-header .aqsp-unhide-marker{cursor:row-resize;opacity:.7;background:repeating-linear-gradient(#2563eb 0 1px,#0000 1px 3px);position:absolute;left:0;right:0}.aqsp-resize-guide{pointer-events:none;background:#2563eb;position:absolute;top:0;left:0}.aqsp-autofill-handle{box-sizing:content-box;pointer-events:auto;cursor:crosshair;background:#2563eb;border:1px solid #fff;width:6px;height:6px;position:absolute;top:0;left:0}.aqsp-autofill-preview{border:1px dashed #16a34a;position:absolute;top:0;left:0}@media (forced-colors:active){.aqsp-band{outline-offset:-2px;background:0 0;outline:2px solid highlight}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after,.aqsp-cell[data-aqsp-invalid]:before{border:1px solid canvastext;width:6px;height:6px}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:0 0;border-color:highlight}.aqsp-selection-fill{outline-offset:-2px;background:0 0;border:none;outline:2px solid highlight}.aqsp-clip-marquee:after{background-image:none;border:2px dashed highlight;animation:none}}.aqsp-col-header-cell[data-aqsp-in-selection],.aqsp-row-header-cell[data-aqsp-in-selection]{color:#1d4ed8;background:#dbeafe;font-weight:600}.aqsp-live-region{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqsp-sink{opacity:0;resize:none;pointer-events:auto;cursor:default;border:0;width:1px;height:1px;padding:0;position:absolute}.aqsp-sink[data-aqsp-editing]{opacity:1;z-index:1;box-sizing:border-box;color:#1f2937;caret-color:#1f2937;white-space:pre;outline-offset:-2px;cursor:text;background:#fff;outline:2px solid #2563eb;padding:0 4px;font-family:inherit;font-size:13px;line-height:1;overflow:hidden}.aqsp-sink[data-aqsp-pointing]{caret-color:#16a34a}.aqsp-popover-layer{pointer-events:none;position:absolute;inset:0;overflow:visible}.aqsp-popover-anchor{pointer-events:none;position:absolute;top:0;left:0}.aqsp-popover-anchor[inert]{visibility:hidden}.aqsp-popover{color:#1f2937;text-align:start;white-space:normal;cursor:default;pointer-events:auto;background:#fff;border:1px solid #d1d5db;border-radius:8px;flex-direction:column;width:320px;max-width:320px;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Noto Sans JP,sans-serif;font-size:13px;line-height:1.4;display:flex;position:absolute;overflow:hidden;box-shadow:0 1px 2px #00000014,0 8px 24px #00000024}.aqsp-popover:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover[data-aqsp-popover-frame=note-tip]{background:#fffbeb;border-color:#f59e0b;box-shadow:0 2px 8px #0000001f}.aqsp-popover-note,.aqsp-popover-comment,.aqsp-popover-link,.aqsp-popover-message{flex-direction:column;min-height:0;padding:10px 12px;display:flex}.aqsp-popover-list{flex-direction:column;min-height:0;padding:6px;display:flex}.aqsp-popover-note-tip{overscroll-behavior:contain;white-space:pre-wrap;overflow-wrap:anywhere;min-height:0;padding:8px 10px;overflow-y:auto}[data-aqsp-popover][data-aqsp-popover-rejected]{border-inline-start:3px solid #dc2626;padding-inline-start:9px}.aqsp-popover-title{color:#374151;align-items:baseline;gap:6px;margin:0 0 6px;font-size:12px;font-weight:600;display:flex}.aqsp-popover-count{color:#6b7280;font-weight:400}.aqsp-popover-textarea,.aqsp-popover-input{width:100%;color:inherit;font:inherit;background:#fff;border:1px solid #d1d5db;border-radius:6px;margin:0;padding:5px 8px;line-height:1.4;display:block}.aqsp-popover-textarea{resize:none;white-space:pre-wrap;flex:auto;height:104px;min-height:56px;overflow:auto}.aqsp-popover-comment .aqsp-popover-textarea{flex:none;height:64px}.aqsp-popover-input{flex:none;height:28px}.aqsp-popover-textarea:focus-visible,.aqsp-popover-input:focus-visible{outline-offset:-1px;border-color:#2563eb;outline:2px solid #2563eb}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-color:#dc2626}.aqsp-popover-textarea[aria-invalid=true]:focus-visible,.aqsp-popover-input[aria-invalid=true]:focus-visible{border-color:#dc2626;outline-color:#dc2626}.aqsp-popover-hint{color:#6b7280;margin:4px 0 0;font-size:12px}[data-aqsp-popover-rejected] .aqsp-popover-hint{color:#b91c1c}.aqsp-popover-field{flex-direction:column;flex:none;gap:3px;margin:0 0 8px;display:flex}.aqsp-popover-field-label{color:#6b7280;font-size:12px}.aqsp-popover-actions{flex:none;align-items:center;gap:6px;margin-top:8px;display:flex}.aqsp-popover-button{color:#1f2937;min-width:56px;height:26px;font:inherit;cursor:pointer;background:#f9fafb;border:1px solid #d1d5db;border-radius:6px;justify-content:center;align-items:center;margin:0;padding:0 10px;font-size:12px;font-weight:500;line-height:1;display:inline-flex}.aqsp-popover-button:not(:disabled):hover{background:#f3f4f6;border-color:#9ca3af}.aqsp-popover-button:focus-visible{outline-offset:1px;outline:2px solid #2563eb}.aqsp-popover-button:disabled{opacity:.5;cursor:not-allowed}.aqsp-popover-button[data-aqsp-popover-save],.aqsp-popover-button[data-aqsp-popover-post]{color:#fff;background:#2563eb;border-color:#2563eb}.aqsp-popover-button[data-aqsp-popover-save]:not(:disabled):hover,.aqsp-popover-button[data-aqsp-popover-post]:not(:disabled):hover{background:#1d4ed8;border-color:#1d4ed8}.aqsp-popover-button[data-aqsp-popover-close]{color:#6b7280;background:0 0;border-color:#0000;width:26px;min-width:0;margin-inline-start:auto;padding:0;font-size:16px;font-weight:400}.aqsp-popover-button[data-aqsp-popover-close]:not(:disabled):hover{color:#1f2937;background:#f3f4f6;border-color:#0000}.aqsp-popover-thread{overscroll-behavior:contain;flex:auto;min-height:48px;max-height:220px;margin:0 0 8px;padding:0;list-style:none;overflow-y:auto}.aqsp-popover-comment-item{border-top:1px solid #f3f4f6;padding:6px 0}.aqsp-popover-comment-item:first-child{border-top:0;padding-top:0}.aqsp-popover-comment-author{color:#111827;font-size:12px;font-weight:600}.aqsp-popover-comment-time{color:#6b7280;font-variant-numeric:tabular-nums;margin-inline-start:6px;font-size:11px}.aqsp-popover-comment-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:2px 0 0}.aqsp-popover-list .aqsp-popover-input{margin-bottom:4px}.aqsp-popover-options{overscroll-behavior:contain;flex:auto;min-height:0;max-height:240px;overflow-y:auto}.aqsp-popover-option{white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:4px;padding:5px 8px;overflow:hidden}.aqsp-popover-option:hover{background:#f3f4f6}.aqsp-popover-option[aria-selected=true]{color:#1e3a8a;background:#dbeafe}.aqsp-popover-option:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover-empty{color:#6b7280;padding:6px 8px;font-size:12px}.aqsp-popover-message{padding-inline-end:40px;position:relative}.aqsp-popover-message .aqsp-popover-title{margin-bottom:2px}.aqsp-popover-message-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.aqsp-popover-message .aqsp-popover-button[data-aqsp-popover-close]{position:absolute;inset-block-start:6px;inset-inline-end:6px}.aqsp-popover-message[data-aqsp-popover-rejected]{background:#fef2f2}.aqsp-popover-message[data-aqsp-popover-rejected] .aqsp-popover-title{color:#b91c1c}@media (forced-colors:active){.aqsp-popover-option:hover,.aqsp-popover-option[aria-selected=true]{outline-offset:-2px;outline:2px solid highlight}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-style:dashed}.aqsp-popover-button[data-aqsp-popover-close]{border-color:buttontext}}[data-aqsp-empty]{width:100%;height:100%;display:block}.aqsp-freeze-divider{background:var(--aqsp-divider-color,#9ca3af);pointer-events:none;position:absolute}.aqsp-freeze-divider-v{width:var(--aqsp-divider-width,2px)}.aqsp-freeze-divider-h{height:var(--aqsp-divider-width,2px)}@media (forced-colors:active){.aqsp-freeze-divider{background:canvastext}}}@layer utilities;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiquants/spreadsheet",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Excel-grade spreadsheet grid for React: multi-cell selection, TSV/HTML clipboard, in-place editing on top of @aiquants/virtualscroll",
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -36,7 +36,7 @@
36
36
  "peerDependencies": {
37
37
  "react": "^19.2.7",
38
38
  "react-dom": "^19.2.7",
39
- "@aiquants/virtualscroll": "^3.4.0"
39
+ "@aiquants/virtualscroll": "^3.5.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@playwright/test": "^1.59.1",
@@ -56,7 +56,7 @@
56
56
  "vite": "^7.2.7",
57
57
  "vite-plugin-dts": "^4.5.4",
58
58
  "vitest": "^3.2.4",
59
- "@aiquants/virtualscroll": "3.4.0"
59
+ "@aiquants/virtualscroll": "3.5.0"
60
60
  },
61
61
  "keywords": [
62
62
  "react",
@@ -177,6 +177,33 @@ export type SpreadsheetProps = {
177
177
  * 位置に依らず常時可視で、可視化の縦成分は no-op。飛行中の変更は全ドラッグを取り消す。
178
178
  */
179
179
  frozenRows?: number
180
+ /**
181
+ * Freezes the LAST N columns at the right edge (v0.9 — the VirtualGrid frozenTrailingCols
182
+ * pass-through; LIVE prop, default 0). Validation SSOT is the engine's fail-fast contract
183
+ * (integer in [0, 128] — RangeError otherwise; the count clamp is leading-wins:
184
+ * effectiveTrailing = min(T, colCount − effectiveLeading)). Trailing columns stay visible at
185
+ * any horizontal scroll — with ONE registered exception: when the leading + trailing extent
186
+ * exceeds the viewport, occluded trailing cells cannot be scrolled into view and keyboard
187
+ * focus paints no visible frame (ADR-19-1). scrollToCell / ensure-visible treat a trailing
188
+ * target as a horizontal no-op. A mid-flight change cancels every in-flight drag without
189
+ * restore (the frozenColumns cancel seam).
190
+ * 末尾 N 列の右端凍結 (v0.9 — VirtualGrid frozenTrailingCols の素通し。ライブ prop、既定 0)。
191
+ * 検証 SSOT はエンジンの fail-fast 契約 ([0, 128] 整数、それ以外 RangeError。件数クランプは
192
+ * leading 勝ち: min(T, colCount − effectiveLeading))。末尾列は任意の横スクロールで可視 —
193
+ * ただし leading + trailing の extent が viewport を超える overlap では遮蔽された末尾セルを
194
+ * スクロールで可視化できず、キーボードフォーカスは可視フレームを描かない (ADR-19-1 の登記済み
195
+ * 帰結)。scrollToCell / ensure-visible は末尾ターゲットを横 no-op として扱う。飛行中の変更は
196
+ * 全ドラッグを復元なしで取り消す (frozenColumns と同じシーム)。
197
+ */
198
+ frozenTrailingColumns?: number
199
+ /**
200
+ * Freezes the LAST N rows at the bottom (v0.9 — the VirtualGrid frozenTrailingRows
201
+ * pass-through; LIVE prop, default 0 — the row twin of frozenTrailingColumns, same engine
202
+ * fail-fast contract and cancel seam). The typical use is a pinned totals row.
203
+ * 末尾 N 行の下端凍結 (v0.9 — frozenTrailingRows の素通し。ライブ prop、既定 0 —
204
+ * frozenTrailingColumns の行双子。エンジン契約・取消シームは同文)。典型は固定合計行。
205
+ */
206
+ frozenTrailingRows?: number
180
207
  /**
181
208
  * Identity-stable contract (same as adapter): an inline arrow here defeats the CellView memo
182
209
  * and turns every host re-render into a full visible re-slice (~800 cells at 16k columns).
@@ -525,6 +552,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
525
552
  defaultColumnWidth = DEFAULT_COLUMN_WIDTH,
526
553
  frozenColumns = 0,
527
554
  frozenRows = 0,
555
+ frozenTrailingColumns = 0,
556
+ frozenTrailingRows = 0,
528
557
  renderCell,
529
558
  onSelectionChange,
530
559
  onCellContextMenu,
@@ -747,6 +776,16 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
747
776
  const windowOriginYRef = useRef(0)
748
777
  const colTrackRef = useRef<HTMLDivElement | null>(null)
749
778
  const windowOriginXRef = useRef(0)
779
+ // ヘッダー帯要素 (選択機械 / オートスクローラーの結線先 — 従来はオートスクローラー節で宣言)
780
+ const colHeaderRef = useRef<HTMLDivElement | null>(null)
781
+ const rowHeaderRef = useRef<HTMLDivElement | null>(null)
782
+ // ヘッダー分割線セグメントのマウント時キャッシュ (v0.9 §2.4 / §4.9 census #12/#13):
783
+ // ヘッダー再描画は同期横パス上の毎通知呼びのため、querySelector 走査ではなく JSX ref で
784
+ // 装着済みノードを直読みする (存在は件数駆動 render 双子 — アンマウントで React が null へ戻す)
785
+ const dividerXLeadingRef = useRef<HTMLDivElement | null>(null)
786
+ const dividerXTrailingRef = useRef<HTMLDivElement | null>(null)
787
+ const dividerYLeadingRef = useRef<HTMLDivElement | null>(null)
788
+ const dividerYTrailingRef = useRef<HTMLDivElement | null>(null)
750
789
  const liveRegionRef = useRef<HTMLDivElement | null>(null)
751
790
 
752
791
  // ---- 選択状態 (React state + 命令読み ref — §6.9-1) ----
@@ -873,11 +912,42 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
873
912
  }, [])
874
913
 
875
914
  /**
876
- * Repaints ONLY the row-header track residual transform. Callers: onScroll, resizeRow, and
915
+ * Equality-suppressed display heal of one header divider segment (v0.9 §4.9 census #12/#13):
916
+ * visibility = band TREE px > 0; existence is the header's count-driven render twin and the
917
+ * geometry stays clip-owned, so this display flip is the ONLY divider write the header
918
+ * repaint path ever makes. The segment arrives through the mount-cached JSX ref (never a
919
+ * per-notification querySelector traversal — the synchronous horizontal pass must not pay
920
+ * a selector scan, least of all a guaranteed miss at F = T = 0). A same-value pass writes
921
+ * nothing — the §5.7 zero-write invariant observes both header repaint writers.
922
+ * ヘッダー分割線セグメント 1 つの等値抑制 display heal (v0.9 §4.9 census #12/#13)。可視 =
923
+ * 帯 TREE px > 0。存在はヘッダーの件数駆動 render 双子、幾何はクリップ所有のままで、ヘッダー
924
+ * 再描画が分割線へ行う書込はこの display フリップだけ。セグメントはマウント時キャッシュの
925
+ * JSX ref 経由 (毎通知の querySelector 走査は同期横パスに載せない — F = T = 0 では全走査
926
+ * ミスが保証される)。同値パスは無書込 — §5.7 のゼロ書込不変量が両書き手を観測する。
927
+ */
928
+ const healHeaderDivider = useCallback((segment: HTMLElement | null, shown: boolean) => {
929
+ // 件数 0 の家族はセグメント未マウント (ref は null) — 無仕事で戻る
930
+ if (segment === null) {
931
+ return
932
+ }
933
+ const next = shown ? "" : "none"
934
+ // 等値抑制 — 定常スクロール wheel 窓中の分割線 style 書込 = 0 の不変量 (§2.4 / §5.7)
935
+ if (segment.style.display !== next) {
936
+ segment.style.display = next
937
+ }
938
+ }, [])
939
+
940
+ /**
941
+ * Repaints the row-header track residual transform. Callers: onScroll, resizeRow, and
877
942
  * RowHeader's layout effect. vy comes from the grid handle (the truth — §7-4; the v0.6 −H_F
878
- * frozen-band term makes this the exact twin of repaintColHeaders).
879
- * 行 track の残差 transform のみを書く命令再描画。vy はグリッドハンドル (§7-4 の真実) から読む
880
- * (v0.6 の −H_F 凍結帯項で repaintColHeaders の完全双子)。
943
+ * frozen-band term makes this the exact twin of repaintColHeaders). v0.9 adds the
944
+ * equality-suppressed display heal of the two y header divider segments (§4.9 census #12 —
945
+ * NO geometry write: the scroll-clip insets are the registered calc() forms that re-resolve
946
+ * through 100% by themselves).
947
+ * 行 track の残差 transform を書く命令再描画。vy はグリッドハンドル (§7-4 の真実) から読む
948
+ * (v0.6 の −H_F 凍結帯項で repaintColHeaders の完全双子)。v0.9 で y ヘッダー分割線 2 セグメント
949
+ * の等値抑制 display heal を追加 (§4.9 census #12 — 幾何書込なし: scroll クリップのインセットは
950
+ * 登記 calc() 形が 100% 再解決で自癒する)。
881
951
  */
882
952
  const repaintHeaders = useCallback(() => {
883
953
  const track = rowTrackRef.current
@@ -888,14 +958,27 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
888
958
  const frozenHeight = handleRef.current?.getFrozenSize().height ?? 0
889
959
  track.style.transform = `translateY(${windowOriginYRef.current - vy - frozenHeight}px)`
890
960
  }
891
- }, [])
961
+ // v0.9 (§4.9 census #12): y ヘッダー分割線の可視 heal — 可視 = 帯 TREE px > 0 (H_F / H_T の
962
+ // ハンドルフィールド)。ハンドル未装着は無書込 (JSX 初期状態のまま = 件数 render が真実)。
963
+ // 両セグメント未マウント (R = T = 0) は getFrozenSize 読みごと省く — 同期横パスの無仕事保証
964
+ const handle = handleRef.current
965
+ if (handle !== null && (dividerYLeadingRef.current !== null || dividerYTrailingRef.current !== null)) {
966
+ const frozen = handle.getFrozenSize()
967
+ healHeaderDivider(dividerYLeadingRef.current, frozen.height > 0)
968
+ healHeaderDivider(dividerYTrailingRef.current, frozen.trailingHeight > 0)
969
+ }
970
+ }, [healHeaderDivider])
892
971
 
893
972
  /**
894
- * Repaints ONLY the column-header track residual transform (§7-5 — the row repaintHeaders
973
+ * Repaints the column-header track residual transform (§7-5 — the row repaintHeaders
895
974
  * twin; the v0.3 --aqsp-hx CSS variable is retired). hx comes from the grid handle (the
896
- * truth — §7-4). Callers: onScroll, resize tails, and ColumnHeader's layout effect.
897
- * 列 track の残差 transform のみを書く命令再描画 (§7-5 — 行 repaintHeaders の双子。v0.3 の
898
- * --aqsp-hx CSS 変数は退役)。hx はグリッドハンドル (§7-4 の真実) から読む。
975
+ * truth — §7-4). Callers: onScroll, resize tails, and ColumnHeader's layout effect. v0.9
976
+ * adds the equality-suppressed display heal of the two x header divider segments (§4.9
977
+ * census #13 — NO geometry write, the exact twin of repaintHeaders).
978
+ * 列 track の残差 transform を書く命令再描画 (§7-5 — 行 repaintHeaders の双子。v0.3 の
979
+ * --aqsp-hx CSS 変数は退役)。hx はグリッドハンドル (§7-4 の真実) から読む。v0.9 で x ヘッダー
980
+ * 分割線 2 セグメントの等値抑制 display heal を追加 (§4.9 census #13 — 幾何書込なし、
981
+ * repaintHeaders の完全双子)。
899
982
  */
900
983
  const repaintColHeaders = useCallback(() => {
901
984
  const track = colTrackRef.current
@@ -906,7 +989,61 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
906
989
  const frozenWidth = handleRef.current?.getFrozenSize().width ?? 0
907
990
  track.style.transform = `translateX(${windowOriginXRef.current - hx - frozenWidth}px)`
908
991
  }
909
- }, [])
992
+ // v0.9 (§4.9 census #13): x ヘッダー分割線の可視 heal (W_F / W_T の TREE px 駆動 — 行と同文。
993
+ // 両セグメント未マウント (F = T = 0) は getFrozenSize 読みごと省く)
994
+ const handle = handleRef.current
995
+ if (handle !== null && (dividerXLeadingRef.current !== null || dividerXTrailingRef.current !== null)) {
996
+ const frozen = handle.getFrozenSize()
997
+ healHeaderDivider(dividerXLeadingRef.current, frozen.width > 0)
998
+ healHeaderDivider(dividerXTrailingRef.current, frozen.trailingWidth > 0)
999
+ }
1000
+ }, [healHeaderDivider])
1001
+
1002
+ // ---- 分割線可視の post-commit heal (v0.9 §2.4 / §2.7) ----
1003
+ const dividerHealRafRef = useRef<number | null>(null)
1004
+ /**
1005
+ * Schedules ONE post-commit divider-visibility heal after a track-resize seam (v0.9 §2.7 —
1006
+ * "T_px = 0 ⇒ no divider" must hold without an interposed scroll). The seam's synchronous
1007
+ * repaint reads the engine's render-captured getFrozenSize (a registered per-render mapping)
1008
+ * BEFORE the engine has re-rendered the new track size, so the divider display would
1009
+ * otherwise lag one geometry transition until the next write pass. One coalesced rAF
1010
+ * re-runs the three imperative writers from the committed getFrozenSize; the equality
1011
+ * suppression keeps this a zero-write pass unless a visibility flip is actually due, and
1012
+ * the F = T = 0 configuration schedules nothing (v0.8 identity — no reservation either).
1013
+ * トラックリサイズシーム後の分割線可視 post-commit heal を 1 回予約 (v0.9 §2.7 —
1014
+ * 「T_px = 0 ⇒ 分割線なし」はスクロール介在なしで成立が要件)。シームの同期 repaint は
1015
+ * エンジンの render 捕捉 getFrozenSize (登記済み毎レンダー写像) をエンジン再レンダー**前**に
1016
+ * 読むため、放置すると分割線 display が次の書込パスまで 1 遷移遅れる。合流 rAF 1 回で
1017
+ * commit 済み getFrozenSize から命令書き手 3 つを再実行 — 等値抑制によりフリップ不要なら
1018
+ * 無書込パス、F = T = 0 構成は予約ごと省く (v0.8 恒等)。
1019
+ */
1020
+ const scheduleDividerHeal = useCallback(() => {
1021
+ // 分割線セグメントが 1 本も存在しない構成 (F = T = 0) は heal 対象なし — 予約も残さない
1022
+ if (dividerXLeadingRef.current === null && dividerXTrailingRef.current === null && dividerYLeadingRef.current === null && dividerYTrailingRef.current === null) {
1023
+ return
1024
+ }
1025
+ // 合流 (バッチリサイズの多発呼びでも 1 フレーム 1 heal)
1026
+ if (dividerHealRafRef.current !== null) {
1027
+ return
1028
+ }
1029
+ dividerHealRafRef.current = requestAnimationFrame(() => {
1030
+ dividerHealRafRef.current = null
1031
+ // ヘッダー 2 面 + overlay (胴体セグメントは layersFor が同パスで heal する) — commit 済み
1032
+ // getFrozenSize からの再実行。残差 transform / 幾何は同値再書込 (エンジンが既に確定済み)
1033
+ repaintHeaders()
1034
+ repaintColHeaders()
1035
+ repaintOverlay()
1036
+ })
1037
+ }, [repaintHeaders, repaintColHeaders, repaintOverlay])
1038
+ // アンマウント時に予約中の heal rAF を回収 (本パッケージの全タイマ / rAF 回収規律)
1039
+ useEffect(
1040
+ () => () => {
1041
+ if (dividerHealRafRef.current !== null) {
1042
+ cancelAnimationFrame(dividerHealRafRef.current)
1043
+ }
1044
+ },
1045
+ [],
1046
+ )
910
1047
 
911
1048
  // ensureCellVisible: §6.6.3 の自前 nearest (1 回構築して keyboard / Shift+F10 へ配布 — §6.9-7)。
912
1049
  // 軸 identity が変わったら作り直す (クロージャが旧軸を掴む stale を防ぐ)
@@ -1265,6 +1402,9 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
1265
1402
  viewStore.bumpColVersion()
1266
1403
  repaintColHeaders()
1267
1404
  repaintOverlay()
1405
+ // 同期 repaint はエンジン再レンダー前の stale getFrozenSize — 分割線可視は
1406
+ // post-commit heal が commit 済み値で整合させる (§2.7 — スクロール介在なし)
1407
+ scheduleDividerHeal()
1268
1408
  return
1269
1409
  }
1270
1410
  for (const entry of entries) {
@@ -1276,8 +1416,10 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
1276
1416
  viewStore.bumpRowGeometry()
1277
1417
  repaintHeaders()
1278
1418
  repaintOverlay()
1419
+ // 行側も同文 (H_F / H_T の分割線可視は commit 済み値で heal — §2.7)
1420
+ scheduleDividerHeal()
1279
1421
  },
1280
- [rowAxis, colAxis, viewStore, repaintColHeaders, repaintHeaders, repaintOverlay],
1422
+ [rowAxis, colAxis, viewStore, repaintColHeaders, repaintHeaders, repaintOverlay, scheduleDividerHeal],
1281
1423
  )
1282
1424
 
1283
1425
  /** Pointer contextmenu relay to onCellContextMenu (§6.4.3-4 sole channel). / pointer 起点の横流し。 */
@@ -1290,8 +1432,6 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
1290
1432
 
1291
1433
  // ---- オートスクローラー 3 種 (セル both / 列ヘッダー x / 行ヘッダー y — §6.4.4 / §6.8) ----
1292
1434
  const cellAutoScroller = useAutoScroller({ handleRef, rowAxis, colAxis, bodyRef, onDragFrame, axis: "both", zoomRef })
1293
- const colHeaderRef = useRef<HTMLDivElement | null>(null)
1294
- const rowHeaderRef = useRef<HTMLDivElement | null>(null)
1295
1435
  const colAutoScroller = useAutoScroller({ handleRef, rowAxis, colAxis, bodyRef, onDragFrame, axis: "x", zoomRef })
1296
1436
  const rowAutoScroller = useAutoScroller({ handleRef, rowAxis, colAxis, bodyRef, onDragFrame, axis: "y", zoomRef })
1297
1437
  // fill 専用の軸別 2 インスタンス (§8.2 — writer も axis も構築時固定。v0.3 のボックス方式では
@@ -1641,19 +1781,23 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
1641
1781
  hideNoteTipRef.current = popovers.hideTip
1642
1782
 
1643
1783
  // ---- コマンド実行 (v0.8 §4.1.13 / ADR-17) ----
1644
- /** The active cell's viewport rect in visual px — the keyboard-origin cellRect recipe (onCellContextMenu twin) for onPasteSpecialRequest. / active セルの視覚 px 矩形 (keyboard 起点 cellRect のレシピ — onCellContextMenu と同式)。 */
1784
+ /** The active cell's viewport rect in visual px via the three-way forward map (v0.9 §4.9 census #11 — the keyboard-origin cellRect recipe, onCellContextMenu twin) for onPasteSpecialRequest. / active セルの視覚 px 矩形 — 3 分岐順写像 (v0.9 §4.9 census #11。keyboard 起点 cellRect のレシピ、onCellContextMenu と同式)。 */
1645
1785
  const keyboardCellRect = useCallback(() => {
1646
1786
  const active = selectionRef.current.active
1647
1787
  // 画面外座標へメニューを出さない (§6.6.1) — 可視化してからハンドルの同期読み (§7-4)
1648
1788
  ensureCellVisible(active)
1649
1789
  const handle = handleRef.current
1650
1790
  const position = handle === null ? { x: 0, y: 0 } : handle.getScrollPosition()
1651
- const frozen = handle === null ? { rows: 0, cols: 0 } : handle.getFrozenSize()
1791
+ // 帯件数と extent も同じ判断で読む (v0.9 計画 §4.9、census #11 — AxisForwardCtx はこの場で
1792
+ // インライン構築、§2.1 規則 1)。detached ハンドルは件数 0 / extent 0 の縮退 (末尾分岐不活性 = v0.8 恒等)
1793
+ const frozen = handle === null ? { rows: 0, cols: 0, trailingRows: 0, trailingCols: 0 } : handle.getFrozenSize()
1794
+ const viewport = handle === null ? { width: 0, height: 0 } : handle.getViewportSize()
1652
1795
  // 両軸とも番兵クランプ (detached の {-1, -1} を座標へ流さない)、ズーム境界で視覚 px へ
1653
1796
  const z = zoomRef.current
1654
1797
  return {
1655
- top: rowToViewportY(rowAxis, active.row, Math.max(0, position.y), frozen.rows) * z,
1656
- left: colToViewportX(colAxis, active.col, Math.max(0, position.x), frozen.cols) * z,
1798
+ // 行 / 列とも凍結パーティション 3 分岐順写像 (末尾は extent アンカー — v0.9 §2.1)。×zoom は写像後 (契約不変)
1799
+ top: rowToViewportY(rowAxis, active.row, { scroll: Math.max(0, position.y), frozenCount: frozen.rows, trailingCount: frozen.trailingRows, extent: viewport.height }) * z,
1800
+ left: colToViewportX(colAxis, active.col, { scroll: Math.max(0, position.x), frozenCount: frozen.cols, trailingCount: frozen.trailingCols, extent: viewport.width }) * z,
1657
1801
  width: colAxis.sizeOf(active.col) * z,
1658
1802
  height: rowAxis.sizeOf(active.row) * z,
1659
1803
  }
@@ -2072,12 +2216,18 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2072
2216
  // 同じ stale 座標遮断だが、座標系は同一グリッドのため選択と編集セッションは保持する
2073
2217
  const prevFrozenColsRef = useRef(frozenColumns)
2074
2218
  const prevFrozenRowsRef = useRef(frozenRows)
2219
+ // v0.9 (§4.9 census #21 — FZ46 教訓): 末尾 2 props も同じ取消 OR に参加する (4 props の
2220
+ // どれかの変化 = 旧 3 分岐パーティションの押下時アンカーが全て陳腐化する)
2221
+ const prevTrailingColsRef = useRef(frozenTrailingColumns)
2222
+ const prevTrailingRowsRef = useRef(frozenTrailingRows)
2075
2223
  useLayoutEffect(() => {
2076
- // 列 / 行いずれの凍結変更も飛行中ドラッグを復元なしで取り消す (R2 是正の縦拡張 —
2077
- // 押下時アンカーは旧パーティション座標系。混成ヒットで誤 fill 確定を防ぐ)
2078
- if (prevFrozenColsRef.current !== frozenColumns || prevFrozenRowsRef.current !== frozenRows) {
2224
+ // 列 / 行・先頭 / 末尾いずれの凍結変更も飛行中ドラッグを復元なしで取り消す (R2 是正の縦拡張 +
2225
+ // v0.9 の末尾拡張 — 押下時アンカーは旧パーティション座標系。混成ヒットで誤 fill 確定を防ぐ)
2226
+ if (prevFrozenColsRef.current !== frozenColumns || prevFrozenRowsRef.current !== frozenRows || prevTrailingColsRef.current !== frozenTrailingColumns || prevTrailingRowsRef.current !== frozenTrailingRows) {
2079
2227
  prevFrozenColsRef.current = frozenColumns
2080
2228
  prevFrozenRowsRef.current = frozenRows
2229
+ prevTrailingColsRef.current = frozenTrailingColumns
2230
+ prevTrailingRowsRef.current = frozenTrailingRows
2081
2231
  engine.cancelDrag()
2082
2232
  colHeaderMachine.cancelDrag()
2083
2233
  rowHeaderMachine.cancelDrag()
@@ -2088,7 +2238,19 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2088
2238
  // (cancelDrag は abortDrag と違いシンク断面を復元しない)
2089
2239
  pointDrag.cancelDrag()
2090
2240
  }
2091
- }, [frozenColumns, frozenRows, engine, colHeaderMachine, rowHeaderMachine, headerResizeMachine, fillMachine, pointDrag])
2241
+ }, [frozenColumns, frozenRows, frozenTrailingColumns, frozenTrailingRows, engine, colHeaderMachine, rowHeaderMachine, headerResizeMachine, fillMachine, pointDrag])
2242
+
2243
+ // ---- 凍結 props フリップの分割線可視整合 (v0.9 §2.4 / §2.7) ----
2244
+ // フリップの同一 commit 内でエンジンは新 props で render 済み (毎レンダー写像の getFrozenSize は
2245
+ // layout effect 時点で確定値)。非表示トラックを含む帯へのフリップ (例: 全 track 幅 0 の列を F = 1 で
2246
+ // 凍結) では新規マウントの分割線セグメントが JSX 初期 display "" のまま px = 0 になるため、
2247
+ // paint 前にここで heal する — スクロール介在なしで「px = 0 ⇒ 分割線なし」を成立させる (§2.7)。
2248
+ // F = T = 0 では両ヘッダー書き手が getFrozenSize 読みごと省き、残差 transform の同値再書込のみ
2249
+ useLayoutEffect(() => {
2250
+ repaintHeaders()
2251
+ repaintColHeaders()
2252
+ repaintOverlay()
2253
+ }, [frozenColumns, frozenRows, frozenTrailingColumns, frozenTrailingRows, repaintHeaders, repaintColHeaders, repaintOverlay])
2092
2254
 
2093
2255
  // ---- dataVersion (外部書込通知 §6.9-2 (b) — Undo / 協調編集) もクリップの破棄条件 ----
2094
2256
  // adapter 外で値が書き戻ると cut 時行列のまま照合が通り、古い指紋の move が外部値を "" で
@@ -2129,6 +2291,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2129
2291
  // §6.8-2 の順序契約の設計内猶予。自己修復するため実害なし)
2130
2292
  repaintHeaders()
2131
2293
  repaintOverlay()
2294
+ // 分割線可視は commit 済み getFrozenSize の post-commit heal で整合 (§2.7)
2295
+ scheduleDividerHeal()
2132
2296
  },
2133
2297
  resizeColumn: (col: number, widthPx: number) => {
2134
2298
  // 対呼び出し (§3.8): colAxis (SSOT) を先に更新し、グリッドの幅木へ通知する。
@@ -2141,6 +2305,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2141
2305
  viewStore.bumpColVersion()
2142
2306
  repaintColHeaders()
2143
2307
  repaintOverlay()
2308
+ // 分割線可視は commit 済み getFrozenSize の post-commit heal で整合 (§2.7)
2309
+ scheduleDividerHeal()
2144
2310
  },
2145
2311
  scrollToCell: (cell: CellCoord, options?: ScrollToCellOptions) => {
2146
2312
  // エンジンのセル狙いジャンプへ素通し (§7-4 の真実。選択は変えない — 純 viewport 移動)。
@@ -2175,7 +2341,7 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2175
2341
  openPopoverRef.current(kind)
2176
2342
  },
2177
2343
  }),
2178
- [rowAxis, colAxis, viewStore, repaintColHeaders, repaintHeaders, repaintOverlay, focusSink, isEditing, rearmSink, adapter, paintedFormatOf, startEdit, requireCommands],
2344
+ [rowAxis, colAxis, viewStore, repaintColHeaders, repaintHeaders, repaintOverlay, scheduleDividerHeal, focusSink, isEditing, rearmSink, adapter, paintedFormatOf, startEdit, requireCommands],
2179
2345
  )
2180
2346
 
2181
2347
  // ---- 空グリッド分岐 (§6.9-1: フックの後・結線の前) ----
@@ -2231,6 +2397,7 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2231
2397
  viewStore={viewStore}
2232
2398
  colAxis={colAxis}
2233
2399
  frozenCols={frozenColumns}
2400
+ frozenTrailingCols={frozenTrailingColumns}
2234
2401
  handleRef={handleRef}
2235
2402
  bandRef={colHeaderRef}
2236
2403
  colTrackRef={colTrackRef}
@@ -2238,6 +2405,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2238
2405
  repaintColHeaders={repaintColHeaders}
2239
2406
  selectionRanges={selection.ranges}
2240
2407
  enableResizeUI={enableResizeUI}
2408
+ dividerLeadingRef={dividerXLeadingRef}
2409
+ dividerTrailingRef={dividerXTrailingRef}
2241
2410
  />
2242
2411
  <RowHeader
2243
2412
  viewStore={viewStore}
@@ -2250,6 +2419,9 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2250
2419
  repaintHeaders={repaintHeaders}
2251
2420
  enableResizeUI={enableResizeUI}
2252
2421
  frozenRows={frozenRows}
2422
+ frozenTrailingRows={frozenTrailingRows}
2423
+ dividerLeadingRef={dividerYLeadingRef}
2424
+ dividerTrailingRef={dividerYTrailingRef}
2253
2425
  />
2254
2426
  <div className="aqsp-body-stack" data-aqsp-body-stack="">
2255
2427
  <GridBody
@@ -2263,6 +2435,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2263
2435
  defaultColumnWidth={defaultColumnWidth}
2264
2436
  frozenColumns={frozenColumns}
2265
2437
  frozenRows={frozenRows}
2438
+ frozenTrailingColumns={frozenTrailingColumns}
2439
+ frozenTrailingRows={frozenTrailingRows}
2266
2440
  renderCell={renderCell}
2267
2441
  onScroll={onScroll}
2268
2442
  onRangeChange={onRangeChange}
@@ -2294,6 +2468,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2294
2468
  enableFillHandle={enableFillHandle}
2295
2469
  frozenCols={frozenColumns}
2296
2470
  frozenRows={frozenRows}
2471
+ trailingCols={frozenTrailingColumns}
2472
+ trailingRows={frozenTrailingRows}
2297
2473
  sinkAriaLabel={resolvedLabels.sinkAriaLabel}
2298
2474
  onSinkMouseDown={onSinkMouseDown}
2299
2475
  editPaintRef={editPaintRef}
@@ -19,6 +19,10 @@
19
19
  * identical style objects (two-tier intern: paint identity, then canonical JSON for the
20
20
  * per-call paints of edge / folded cells).
21
21
  *
22
+ * v0.9 trailing freeze (plan §4.15): `frozenTrailingColumns` / `frozenTrailingRows` are
23
+ * engine-validated pass-throughs onto VirtualGrid's `frozenTrailingCols` / `frozenTrailingRows`
24
+ * — validation SSOT is the engine's fail-fast contract, no second layer here (§1.1).
25
+ *
22
26
  * グリッド本体。VirtualGrid 結線 (両軸) とセルレンダラーを所有する。v0.4 から横軸は VirtualGrid
23
27
  * の所有 (量子化列アンカー + 残差 transform + 横バー) — v0.3 の列スタック (useColumnWindow /
24
28
  * --aqsp-hx CSS 変数 / 軸原点絶対 left / 自前 HScrollBar) は設計計画 §7-1 に従い削除。
@@ -33,6 +37,10 @@
33
37
  * 全読みは能力分岐 (`adapter.x === undefined` ⇒ v0.1 の属性なしセル)、条件付き書式索引は root の宣言能力 (未指定 ⇒
34
38
  * base 書式のみ)、無変化セルは同一の style object を保つ (2 段 intern: paint identity → 端 / 畳込み
35
39
  * セルの呼出毎 paint は正準 JSON)。
40
+ *
41
+ * v0.9 末尾凍結 (計画 §4.15): `frozenTrailingColumns` / `frozenTrailingRows` は VirtualGrid の
42
+ * `frozenTrailingCols` / `frozenTrailingRows` へのエンジン検証素通し — 検証 SSOT はエンジンの
43
+ * fail-fast 契約で、ここに第二検証層は置かない (§1.1)。
36
44
  */
37
45
 
38
46
  import { VirtualGrid, type VirtualGridHandle, type VirtualGridRange } from "@aiquants/virtualscroll"
@@ -257,6 +265,10 @@ type GridBodyProps = {
257
265
  frozenColumns: number
258
266
  /** Frozen leading rows (v0.6 — VirtualGrid frozenLeadingRows pass-through; engine-validated). / 先頭凍結行数 (v0.6 — エンジン検証の素通し)。 */
259
267
  frozenRows: number
268
+ /** Trailing frozen columns (v0.9 — VirtualGrid frozenTrailingCols engine-validated pass-through; no second validation layer — §1.1 SSOT). / 末尾凍結列数 (v0.9 — VirtualGrid frozenTrailingCols のエンジン検証素通し。第二検証層なし — §1.1 SSOT)。 */
269
+ frozenTrailingColumns: number
270
+ /** Trailing frozen rows (v0.9 — VirtualGrid frozenTrailingRows engine-validated pass-through; the row twin). / 末尾凍結行数 (v0.9 — frozenTrailingRows のエンジン検証素通し。行双子)。 */
271
+ frozenTrailingRows: number
260
272
  renderCell?: (ctx: RenderCellContext) => ReactNode
261
273
  /** 2D scroll notification from the grid handle (the truth — §7-4). / グリッドハンドル発の 2 軸スクロール通知 (§7-4 の真実側)。 */
262
274
  onScroll: (position: { x: number; y: number }) => void
@@ -303,6 +315,8 @@ const GridBodyInner = ({
303
315
  defaultColumnWidth,
304
316
  frozenColumns,
305
317
  frozenRows,
318
+ frozenTrailingColumns,
319
+ frozenTrailingRows,
306
320
  renderCell,
307
321
  onScroll,
308
322
  onRangeChange,
@@ -467,6 +481,8 @@ const GridBodyInner = ({
467
481
  colCount={adapter.colCount}
468
482
  frozenLeadingCols={frozenColumns}
469
483
  frozenLeadingRows={frozenRows}
484
+ frozenTrailingCols={frozenTrailingColumns}
485
+ frozenTrailingRows={frozenTrailingRows}
470
486
  getRowHeight={getRowHeight}
471
487
  getColWidth={getColWidth}
472
488
  getCell={getCell}