Spaces:
Running
Running
| <html lang="en" data-visualize-standalone> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <meta name="referrer" content="no-referrer"> | |
| <title>Alphago Move 37</title> | |
| <style>:root { | |
| color-scheme: light dark; | |
| background-color: transparent ; | |
| /* Agent-facing contract; keep in sync with SKILL.md. */ | |
| --background: var( | |
| --main-surface-primary, | |
| light-dark(rgb(255 255 255), rgb(24 24 24)) | |
| ); | |
| --foreground: light-dark(rgb(26 28 31), rgb(255 255 255)); | |
| --card: color-mix(in oklab, var(--foreground) 5%, transparent); | |
| --card-foreground: var(--foreground); | |
| --popover: light-dark(rgb(255 255 255), rgb(45 45 45)); | |
| --popover-foreground: var(--foreground); | |
| --primary: light-dark(rgb(51 156 255), rgb(131 195 255)); | |
| --primary-foreground: light-dark(rgb(255 255 255), rgb(13 13 13)); | |
| --secondary: light-dark(rgb(255 255 255 / 96%), rgb(54 54 54 / 96%)); | |
| --secondary-foreground: var(--foreground); | |
| --muted: color-mix(in srgb, var(--foreground) 10%, transparent); | |
| --muted-foreground: light-dark( | |
| rgb(26 28 31 / 49.4%), | |
| rgb(255 255 255 / 49.8%) | |
| ); | |
| --accent: light-dark(rgb(229 242 255), rgb(13 39 63)); | |
| --accent-foreground: var(--primary); | |
| --destructive: light-dark(rgb(226 85 7), rgb(255 133 73)); | |
| --border: light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%)); | |
| --input: light-dark( | |
| rgb(26 28 31 / 11.8%), | |
| color-mix(in oklab, rgb(0 0 0) 10%, transparent) | |
| ); | |
| --ring: light-dark(rgb(51 156 255), rgb(131 195 255 / 76%)); | |
| --font-size-base: 14px; | |
| --red: light-dark(rgb(186 38 35), rgb(250 66 62)); | |
| --green: light-dark(rgb(0 162 64), rgb(64 201 119)); | |
| /* Internal implementation variables; not part of the agent contract. */ | |
| --font-sans: -apple-system, system-ui, "Segoe UI", sans-serif; | |
| --font-mono: | |
| ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", | |
| monospace; | |
| --font-size-normal: max(11px, var(--font-size-base)); | |
| --font-size-tooltip: calc(var(--font-size-base) - 1px); | |
| --font-size-small: max(11px, calc(var(--font-size-base) - 2px)); | |
| --font-size-h1: calc(var(--font-size-normal) * 1.7142857143); | |
| --font-size-h2: calc(var(--font-size-normal) * 1.4285714286); | |
| --font-size-h3: calc(var(--font-size-normal) * 1.2857142857); | |
| --font-weight-normal: 430; | |
| --font-weight-medium: 500; | |
| --line-height-normal: calc(var(--font-size-normal) * 1.5); | |
| --line-height-tooltip: calc(var(--font-size-tooltip) * 1.4285714286); | |
| --line-height-small: calc(var(--font-size-small) + 4px); | |
| --radius: 10px; | |
| --radius-sm: calc(var(--radius) * 0.6); | |
| --radius-md: calc(var(--radius) * 0.8); | |
| --radius-lg: var(--radius); | |
| --radius-2xl: calc(var(--radius) * 1.6); | |
| --radius-full: 9999px; | |
| --shadow-sm: 0 1px 2px -1px rgb(0 0 0 / 8%); | |
| --checkmark-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17'%3E%3Cpath d='M12.8961 3.64101C13.1297 3.41418 13.4984 3.37523 13.7779 3.56581C14.0571 3.75635 14.1554 4.11331 14.0299 4.41347L13.9615 4.53847L7.71151 13.7045C7.59411 13.8767 7.4063 13.9877 7.19881 14.0072C6.99136 14.0267 6.78564 13.9533 6.63826 13.806L2.88826 10.056L2.79842 9.9457C2.6192 9.67407 2.64927 9.30496 2.88826 9.06581C3.12738 8.82669 3.49647 8.79676 3.76815 8.97597L3.8785 9.06581L7.03084 12.2182L12.8053 3.74941L12.8961 3.64101Z'/%3E%3C/svg%3E"); | |
| /* Legacy aliases; not part of the current agent contract. */ | |
| --viz-bg: transparent; | |
| --viz-panel: var(--card); | |
| --viz-border: var(--border); | |
| --viz-text: var(--foreground); | |
| --viz-muted: var(--muted-foreground); | |
| --viz-accent: var(--primary); | |
| --viz-accent-text: var(--primary-foreground); | |
| --viz-accent-bg: var(--accent); | |
| --viz-font-size: var(--font-size-base); | |
| --viz-warning: var(--destructive); | |
| --color-background-primary: var(--background); | |
| --color-text-primary: var(--foreground); | |
| --color-border-secondary: var(--border); | |
| } | |
| :root[data-visualize-standalone] { | |
| background-color: var(--background) ; | |
| } | |
| /* Generic mobile code-block hosts provide light/dark mode but no series palette. | |
| AppBlock hosts set all six variables themselves. */ | |
| :root:not([data-app-block-surface]) { | |
| --viz-series-1: var(--primary); | |
| --viz-series-2: light-dark(#f3883b, #f59a56); | |
| --viz-series-3: light-dark(#5dc977, #74d58b); | |
| --viz-series-4: light-dark(#eb77b1, #f08fc0); | |
| --viz-series-5: light-dark(#9b79ec, #aa91ef); | |
| --viz-series-6: light-dark(#3ab9b1, #5acbc2); | |
| } | |
| :root[data-theme="light"] { | |
| color-scheme: light; | |
| } | |
| :root[data-theme="dark"] { | |
| color-scheme: dark; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| } | |
| html > body { | |
| margin: 0; | |
| padding: 5px; | |
| color: var(--foreground); | |
| background: transparent ; | |
| font-family: var(--font-sans); | |
| font-size: var(--font-size-normal); | |
| font-weight: var(--font-weight-normal); | |
| line-height: var(--line-height-normal); | |
| } | |
| :root:not([data-app-block-surface]) > body { | |
| padding: 12px; | |
| } | |
| a { | |
| color: color-mix(in srgb, var(--viz-accent) 80%, var(--viz-text) 20%); | |
| cursor: pointer; | |
| font-weight: var(--font-weight-medium); | |
| text-decoration: none; | |
| text-underline-offset: 2px; | |
| } | |
| a:is(:hover, :focus-visible) { | |
| text-decoration-line: underline; | |
| text-decoration-style: dashed; | |
| text-decoration-thickness: 0.5px; | |
| } | |
| h1, | |
| h2, | |
| h3, | |
| h4, | |
| h5, | |
| h6, | |
| p { | |
| margin-block: 0; | |
| } | |
| h1 { | |
| font-size: var(--font-size-h1); | |
| font-weight: var(--font-weight-medium); | |
| line-height: 1.25; | |
| } | |
| h2 { | |
| font-size: var(--font-size-h2); | |
| font-weight: var(--font-weight-medium); | |
| line-height: 1.25; | |
| } | |
| h3, | |
| h4, | |
| h5, | |
| h6 { | |
| font-size: var(--font-size-h3); | |
| font-weight: var(--font-weight-medium); | |
| line-height: 1.3; | |
| } | |
| b, | |
| strong, | |
| th { | |
| font-weight: var(--font-weight-medium); | |
| } | |
| code:not(pre code) { | |
| display: inline; | |
| padding: 1px 6px; | |
| border-radius: var(--radius-sm); | |
| background: var(--muted); | |
| font-family: var(--font-mono); | |
| font-size: 0.92em; | |
| overflow-wrap: anywhere; | |
| -webkit-box-decoration-break: clone; | |
| box-decoration-break: clone; | |
| word-break: break-word; | |
| } | |
| .table-responsive { | |
| width: 100%; | |
| overflow-x: auto; | |
| scrollbar-width: thin; | |
| } | |
| .table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| color: var(--foreground); | |
| font: inherit; | |
| text-align: start; | |
| } | |
| .table :is(th, td) { | |
| padding-block: 10px; | |
| padding-inline: 0 24px; | |
| overflow-wrap: anywhere; | |
| border-bottom: 1px solid var(--border); | |
| text-align: start; | |
| vertical-align: top; | |
| } | |
| .table-responsive > .table :is(th, td) { | |
| overflow-wrap: break-word; | |
| } | |
| .table :is(th, td):last-child { | |
| padding-inline-end: 0; | |
| } | |
| .table :is(caption, thead th) { | |
| font-weight: 600; | |
| } | |
| .table thead th { | |
| padding-block: 8px; | |
| border-bottom-color: color-mix(in srgb, var(--foreground) 16%, transparent); | |
| } | |
| .table tbody tr:last-child :is(th, td) { | |
| border-bottom: 0; | |
| } | |
| .table.table-sm :is(th, td) { | |
| padding-block: 6px; | |
| } | |
| .table.table-sm :is(th, td):not(:last-child) { | |
| padding-inline-end: 16px; | |
| } | |
| .table :is(.text-end, [align="right"]) { | |
| text-align: end; | |
| font-variant-numeric: tabular-nums; | |
| } | |
| .table :is(.text-center, [align="center"]) { | |
| text-align: center; | |
| } | |
| .table .text-nowrap { | |
| white-space: nowrap; | |
| } | |
| #widget { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| width: 100%; | |
| padding: 0; | |
| background: transparent ; | |
| } | |
| .card { | |
| min-width: 0; | |
| padding: 12px; | |
| overflow: hidden; | |
| overflow-wrap: break-word; | |
| border-radius: var(--radius-2xl); | |
| color: var(--card-foreground); | |
| background: var(--card); | |
| } | |
| #widget > :not(.card) { | |
| width: 100% ; | |
| max-width: none ; | |
| margin: 0 ; | |
| padding: 0 ; | |
| border: 0 ; | |
| border-radius: 0 ; | |
| background: transparent ; | |
| box-shadow: none ; | |
| } | |
| .tooltip { | |
| position: fixed; | |
| z-index: 50; | |
| top: 0; | |
| left: 0; | |
| width: max-content; | |
| max-width: min( | |
| 20rem, | |
| var(--tooltip-available-width, calc(100vw - 10px)), | |
| calc(100vw - 10px) | |
| ); | |
| max-height: min( | |
| var(--tooltip-available-height, calc(100vh - 10px)), | |
| calc(100vh - 10px) | |
| ); | |
| padding: 4px 8px; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-lg); | |
| color: var(--popover-foreground); | |
| background: var(--popover); | |
| box-shadow: none; | |
| font-size: var(--font-size-tooltip); | |
| line-height: var(--line-height-tooltip); | |
| overflow-wrap: break-word; | |
| white-space: normal; | |
| pointer-events: none; | |
| user-select: none; | |
| } | |
| /* The bundled tooltip runtime owns [data-tooltip]. AppBlock's CSS-only | |
| pseudo-tooltip can widen dense grids even while hidden. */ | |
| main [data-tooltip]::after { | |
| content: none; | |
| } | |
| .viz-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(max(180px, 24%), 1fr)); | |
| gap: 10px; | |
| } | |
| .viz-stat { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 2px; | |
| } | |
| .viz-stat-value { | |
| font-size: var(--font-size-h2); | |
| font-weight: var(--font-weight-medium); | |
| line-height: 1.25; | |
| } | |
| .viz-row { | |
| display: flex; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .viz-badge { | |
| padding: 3px 8px; | |
| border-radius: var(--radius-full); | |
| color: var(--accent-foreground); | |
| background: var(--accent); | |
| font-weight: var(--font-weight-medium); | |
| } | |
| small, | |
| .text-small, | |
| .viz-badge { | |
| font-size: var(--font-size-small); | |
| line-height: var(--line-height-small); | |
| } | |
| .text-muted { | |
| color: var(--muted-foreground); | |
| } | |
| .sr-only { | |
| position: absolute; | |
| width: 1px; | |
| height: 1px; | |
| padding: 0; | |
| overflow: hidden; | |
| clip: rect(0, 0, 0, 0); | |
| white-space: nowrap; | |
| border: 0; | |
| } | |
| .viz-controls { | |
| display: flex; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .viz-controls > .form-label { | |
| display: grid; | |
| min-width: min(100%, 260px); | |
| flex: 1 1 280px; | |
| grid-template-columns: minmax(0, 1fr) auto; | |
| align-items: baseline; | |
| gap: 2px 12px; | |
| margin-bottom: 0; | |
| } | |
| .viz-controls > .form-label > :is(.form-control, .form-range, .form-select) { | |
| grid-column: 1 / -1; | |
| } | |
| .btn, | |
| .form-check-input, | |
| .form-control, | |
| .form-range, | |
| .form-select { | |
| font: inherit; | |
| } | |
| .btn { | |
| appearance: button; | |
| display: inline-flex; | |
| inline-size: fit-content; | |
| max-inline-size: 100%; | |
| min-height: 28px; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 4px; | |
| margin: 0; | |
| padding: 0 8px; | |
| -webkit-app-region: no-drag; | |
| border: 1px solid var(--input); | |
| border-radius: var(--radius-lg); | |
| color: var(--secondary-foreground); | |
| background: var(--secondary); | |
| cursor: var(--cursor-interaction, pointer); | |
| text-align: center; | |
| text-decoration: none; | |
| white-space: nowrap; | |
| user-select: none; | |
| -webkit-font-smoothing: antialiased; | |
| } | |
| .btn:is(.btn-block, .viz-tile) { | |
| inline-size: 100%; | |
| } | |
| .btn.viz-tile { | |
| min-width: 0; | |
| overflow-wrap: anywhere; | |
| white-space: normal; | |
| } | |
| a.btn { | |
| cursor: pointer; | |
| text-decoration: none; | |
| } | |
| .btn:not(:disabled):hover { | |
| background: color-mix(in srgb, var(--foreground) 6%, var(--secondary)); | |
| } | |
| .btn-primary { | |
| border-color: transparent; | |
| color: var(--interactive-label-primary-default, var(--primary-foreground)); | |
| background: var(--interactive-bg-primary-default, var(--foreground)); | |
| background-clip: padding-box; | |
| } | |
| .btn-primary .text-muted { | |
| color: color-mix( | |
| in srgb, | |
| var(--interactive-label-primary-default, var(--primary-foreground)) 50%, | |
| transparent | |
| ); | |
| } | |
| .btn-primary:not(:disabled):hover { | |
| background: color-mix(in srgb, var(--foreground) 80%, transparent); | |
| background-clip: padding-box; | |
| } | |
| .btn-ghost { | |
| border-color: transparent; | |
| color: var(--muted-foreground); | |
| background: transparent; | |
| } | |
| .btn-ghost:not(:disabled):hover { | |
| color: var(--foreground); | |
| background: color-mix(in srgb, var(--foreground) 6%, var(--secondary)); | |
| } | |
| .btn:disabled { | |
| cursor: not-allowed; | |
| opacity: 0.4; | |
| } | |
| [data-lucide] { | |
| stroke-width: 1.6; | |
| } | |
| .form-label { | |
| display: block; | |
| margin-bottom: 6px; | |
| color: var(--foreground); | |
| } | |
| .form-control { | |
| display: block; | |
| width: 100%; | |
| min-height: 28px; | |
| padding: 0 8px; | |
| outline: none; | |
| border: 1px solid var(--input); | |
| border-radius: var(--radius-lg); | |
| color: var(--foreground); | |
| background: var(--secondary); | |
| } | |
| .form-control::placeholder { | |
| color: var(--muted-foreground); | |
| } | |
| .form-control[type="file"] { | |
| padding: 0; | |
| overflow: hidden; | |
| cursor: var(--cursor-interaction, pointer); | |
| } | |
| .form-control[type="file"]::file-selector-button { | |
| min-height: 26px; | |
| margin-right: 8px; | |
| padding: 0 8px; | |
| border: 0; | |
| border-right: 1px solid var(--input); | |
| color: var(--secondary-foreground); | |
| background: var(--secondary); | |
| cursor: inherit; | |
| font: inherit; | |
| } | |
| .form-control[type="file"]:not(:disabled):hover::file-selector-button { | |
| background: color-mix(in srgb, var(--foreground) 6%, var(--secondary)); | |
| } | |
| .form-control-color[type="color"] { | |
| width: 40px; | |
| height: 28px; | |
| padding: 3px; | |
| cursor: var(--cursor-interaction, pointer); | |
| } | |
| .form-control-color[type="color"]::-webkit-color-swatch-wrapper { | |
| padding: 0; | |
| } | |
| .form-control-color[type="color"]::-webkit-color-swatch { | |
| border: 0; | |
| border-radius: calc(var(--radius-lg) - 4px); | |
| } | |
| textarea.form-control { | |
| height: auto; | |
| min-height: 72px; | |
| padding: 8px 10px; | |
| resize: vertical; | |
| } | |
| .form-control:focus-visible { | |
| border-color: var(--ring); | |
| box-shadow: inset 0 0 0 1px var(--ring); | |
| } | |
| .form-control:disabled, | |
| .form-select:disabled { | |
| cursor: not-allowed; | |
| opacity: 0.4; | |
| } | |
| .form-select { | |
| appearance: none; | |
| display: block; | |
| width: 100%; | |
| min-height: 28px; | |
| margin: 0; | |
| padding: 0 32px 0 8px; | |
| outline: none; | |
| border: 1px solid var(--input); | |
| border-radius: var(--radius-lg); | |
| color: var(--foreground); | |
| background-color: var(--secondary); | |
| background-image: | |
| linear-gradient(45deg, transparent 50%, var(--muted-foreground) 50%), | |
| linear-gradient(135deg, var(--muted-foreground) 50%, transparent 50%); | |
| background-position: | |
| calc(100% - 14px) 50%, | |
| calc(100% - 10px) 50%; | |
| background-repeat: no-repeat; | |
| background-size: 4px 4px; | |
| cursor: var(--cursor-interaction, default); | |
| } | |
| .form-select:not(:disabled):hover { | |
| background-color: color-mix(in srgb, var(--foreground) 6%, var(--secondary)); | |
| } | |
| .form-select:focus-visible { | |
| border-color: var(--ring); | |
| box-shadow: inset 0 0 0 1px var(--ring); | |
| } | |
| .form-check { | |
| display: flex; | |
| min-height: 20px; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .form-check-input { | |
| appearance: none; | |
| width: 14px; | |
| height: 14px; | |
| flex: 0 0 auto; | |
| margin: 0; | |
| border: 1px solid var(--input); | |
| color: var(--primary-foreground); | |
| background-color: transparent; | |
| cursor: var(--cursor-interaction, default); | |
| transition: | |
| background-color 150ms, | |
| border-color 150ms, | |
| box-shadow 150ms; | |
| } | |
| .form-check:not(.form-switch) .form-check-input[type="checkbox"] { | |
| border-color: var(--input); | |
| border-radius: var(--radius-sm); | |
| background-color: var(--secondary); | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .form-check:not(.form-switch) | |
| .form-check-input:not(:disabled):not(:checked):hover { | |
| background-color: var(--card); | |
| } | |
| .form-check:not(.form-switch) .form-check-input[type="checkbox"]:checked { | |
| border-color: var(--primary); | |
| background-color: var(--primary); | |
| } | |
| .form-check:not(.form-switch) | |
| .form-check-input[type="checkbox"]:checked::before { | |
| display: block; | |
| width: 100%; | |
| height: 100%; | |
| background: var(--primary-foreground); | |
| content: ""; | |
| mask: var(--checkmark-image) center / 12px 12px no-repeat; | |
| } | |
| .form-check-input[type="radio"] { | |
| width: 14px; | |
| height: 14px; | |
| border-radius: var(--radius-full); | |
| } | |
| .form-check-input[type="radio"]:checked { | |
| border: 2px solid var(--primary); | |
| background: | |
| radial-gradient(circle, var(--primary-foreground) 0 2.5px, transparent 3px), | |
| var(--primary); | |
| } | |
| .form-check:not(.form-switch) .form-check-input:focus-visible { | |
| outline: 2px solid var(--ring); | |
| outline-offset: 2px; | |
| } | |
| .form-check:not(.form-switch) .form-check-input:disabled { | |
| cursor: not-allowed; | |
| pointer-events: none; | |
| } | |
| .form-check:not(.form-switch) .form-check-input:disabled + .form-check-label { | |
| cursor: not-allowed; | |
| } | |
| .form-switch .form-check-input:disabled, | |
| .form-switch .form-check-input:disabled + .form-check-label { | |
| cursor: not-allowed; | |
| opacity: 0.6; | |
| } | |
| .form-check-label { | |
| color: var(--foreground); | |
| cursor: var(--cursor-interaction, default); | |
| } | |
| .form-switch .form-check-input { | |
| position: relative; | |
| width: 32px; | |
| height: 20px; | |
| border: 0; | |
| border-radius: var(--radius-full); | |
| background: var(--muted); | |
| box-shadow: none; | |
| transition: background-color 200ms cubic-bezier(0, 0, 0.2, 1); | |
| } | |
| .form-switch .form-check-input::before { | |
| position: absolute; | |
| top: 50%; | |
| left: 0; | |
| width: 16px; | |
| height: 16px; | |
| box-sizing: border-box; | |
| border: 1px solid light-dark(var(--primary-foreground), var(--foreground)); | |
| border-radius: var(--radius-full); | |
| background: light-dark(var(--primary-foreground), var(--foreground)); | |
| box-shadow: var(--shadow-sm); | |
| content: ""; | |
| transform: translate(2px, -50%); | |
| transition: transform 200ms cubic-bezier(0, 0, 0.2, 1); | |
| } | |
| .form-switch .form-check-input:checked { | |
| background: var(--primary); | |
| } | |
| .form-switch .form-check-input:checked::before { | |
| transform: translate(14px, -50%); | |
| } | |
| .form-switch .form-check-input:focus-visible { | |
| box-shadow: 0 0 0 2px var(--ring); | |
| } | |
| .form-range { | |
| appearance: none; | |
| display: block; | |
| width: 100%; | |
| height: 28px; | |
| flex: 1; | |
| margin: 0; | |
| padding: 0; | |
| outline: none; | |
| border: 0; | |
| accent-color: var(--primary); | |
| background: linear-gradient( | |
| color-mix(in srgb, var(--foreground) 7%, transparent), | |
| color-mix(in srgb, var(--foreground) 7%, transparent) | |
| ) | |
| center / 100% 2px no-repeat; | |
| } | |
| .form-range::-webkit-slider-runnable-track { | |
| height: 28px; | |
| background: transparent; | |
| } | |
| .form-range::-webkit-slider-thumb { | |
| appearance: none; | |
| width: 20px; | |
| height: 20px; | |
| margin-top: 4px; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-full); | |
| background: light-dark(var(--primary-foreground), var(--foreground)); | |
| } | |
| .form-range:focus-visible::-webkit-slider-thumb { | |
| border-color: var(--ring); | |
| box-shadow: inset 0 0 0 1px var(--ring); | |
| } | |
| .form-range::-moz-range-track { | |
| height: 28px; | |
| background: transparent; | |
| } | |
| .form-range::-moz-range-thumb { | |
| width: 20px; | |
| height: 20px; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-full); | |
| background: light-dark(var(--primary-foreground), var(--foreground)); | |
| } | |
| .form-range:focus-visible::-moz-range-thumb { | |
| border-color: var(--ring); | |
| box-shadow: inset 0 0 0 1px var(--ring); | |
| } | |
| .form-range:disabled { | |
| cursor: not-allowed; | |
| opacity: 0.4; | |
| } | |
| .btn:not(.btn-primary, .viz-tile):is( | |
| [aria-pressed="true"], | |
| [aria-selected="true"], | |
| .is-selected | |
| ) { | |
| border-color: var(--primary); | |
| color: var(--primary-foreground); | |
| background: var(--primary); | |
| } | |
| .btn.viz-tile:is([aria-pressed="true"], [aria-selected="true"], .is-selected) { | |
| border-color: var(--primary); | |
| box-shadow: inset 0 0 0 1px var(--primary); | |
| } | |
| .btn:focus-visible { | |
| outline: 2px solid var(--ring); | |
| outline-offset: 2px; | |
| } | |
| svg { | |
| display: block; | |
| max-width: 100%; | |
| height: auto; | |
| } | |
| #widget > svg { | |
| width: 100%; | |
| } | |
| .text-warning, | |
| .text-destructive { | |
| color: var(--destructive); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="alphago-move-37" class="move37-shell"> | |
| <div class="viz-controls" aria-label="Replay controls"> | |
| <button type="button" class="btn" data-action="start"><i data-lucide="skip-back" aria-hidden="true"></i> Start</button> | |
| <button type="button" class="btn" data-action="previous"><i data-lucide="chevron-left" aria-hidden="true"></i> Previous</button> | |
| <button type="button" class="btn btn-primary" data-action="play"><i data-lucide="play" aria-hidden="true"></i> Play</button> | |
| <button type="button" class="btn" data-action="next">Next <i data-lucide="chevron-right" aria-hidden="true"></i></button> | |
| <button type="button" class="btn" data-action="move37"><i data-lucide="sparkles" aria-hidden="true"></i> Jump to 37</button> | |
| </div> | |
| <div class="move37-stage"> | |
| <svg class="move37-board" viewBox="0 0 640 640" role="img" aria-labelledby="move37-title move37-desc"> | |
| <title id="move37-title">AlphaGo versus Lee Sedol, Game 2 Go board</title> | |
| <desc id="move37-desc">Interactive replay of the first 50 moves, highlighting AlphaGo's famous black move 37 at P10.</desc> | |
| <defs> | |
| <radialGradient id="move37-black" cx="35%" cy="28%" r="70%"><stop offset="0" stop-color="#626262"/><stop offset="0.38" stop-color="#202020"/><stop offset="1" stop-color="#050505"/></radialGradient> | |
| <radialGradient id="move37-white" cx="35%" cy="28%" r="70%"><stop offset="0" stop-color="#ffffff"/><stop offset="0.62" stop-color="#e8e8e8"/><stop offset="1" stop-color="#bdbdbd"/></radialGradient> | |
| <filter id="move37-shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="1.5" dy="2.5" stdDeviation="2" flood-color="#000000" flood-opacity="0.28"/></filter> | |
| </defs> | |
| <rect x="18" y="18" width="604" height="604" rx="8" class="board-field"/> | |
| <g data-layer="grid"></g> | |
| <g data-layer="stars"></g> | |
| <g data-layer="coordinates"></g> | |
| <g data-layer="stones"></g> | |
| <g data-layer="highlight"></g> | |
| </svg> | |
| <div class="card move37-detail" aria-live="polite"> | |
| <div class="move37-kicker" data-role="kicker">Opening position</div> | |
| <div class="viz-stat-value" data-role="headline">Move 0 of 50</div> | |
| <div data-role="detail">AlphaGo plays Black. Lee Sedol plays White.</div> | |
| </div> | |
| </div> | |
| <div class="move37-progress" aria-label="Replay progress"> | |
| <label class="form-label" for="move37-range">Move <span data-role="move-number">0</span></label> | |
| <input id="move37-range" class="form-range" type="range" min="0" max="50" value="0" step="1"> | |
| </div> | |
| </div> | |
| <style> | |
| #alphago-move-37 { color: var(--foreground); width: 100%; } | |
| #alphago-move-37 .move37-stage { display: grid; grid-template-columns: minmax(0, 1fr) minmax(210px, 0.42fr); gap: 16px; align-items: center; margin-top: 12px; } | |
| #alphago-move-37 .move37-board { width: 100%; max-width: 640px; height: auto; display: block; } | |
| #alphago-move-37 .board-field { fill: color-mix(in srgb, var(--viz-series-1) 26%, var(--card)); stroke: var(--border); stroke-width: 2; } | |
| #alphago-move-37 .board-line { stroke: color-mix(in srgb, var(--foreground) 64%, transparent); stroke-width: 1.35; } | |
| #alphago-move-37 .star { fill: color-mix(in srgb, var(--foreground) 78%, transparent); } | |
| #alphago-move-37 .coord { fill: var(--muted-foreground); font: 500 12px system-ui, sans-serif; text-anchor: middle; dominant-baseline: middle; } | |
| #alphago-move-37 .stone { filter: url(#move37-shadow); } | |
| #alphago-move-37 .stone-number { font: 500 10px system-ui, sans-serif; text-anchor: middle; dominant-baseline: central; pointer-events: none; } | |
| #alphago-move-37 .move37-ring { fill: none; stroke: var(--viz-series-2); stroke-width: 5; } | |
| #alphago-move-37 .move37-pulse { fill: color-mix(in srgb, var(--viz-series-2) 24%, transparent); stroke: var(--viz-series-2); stroke-width: 2; } | |
| #alphago-move-37 .move37-label { fill: var(--foreground); font: 500 14px system-ui, sans-serif; text-anchor: middle; } | |
| #alphago-move-37 .move37-detail { min-height: 150px; display: grid; align-content: center; gap: 8px; } | |
| #alphago-move-37 .move37-kicker { color: var(--muted-foreground); } | |
| #alphago-move-37 .move37-progress { margin-top: 12px; } | |
| @media (max-width: 620px) { | |
| #alphago-move-37 .move37-stage { grid-template-columns: 1fr; } | |
| #alphago-move-37 .move37-detail { min-height: auto; } | |
| } | |
| @media (prefers-reduced-motion: no-preference) { | |
| #alphago-move-37 .move37-pulse { animation: move37-pulse 1.4s ease-in-out infinite alternate; } | |
| @keyframes move37-pulse { from { opacity: .4; transform: scale(.82); transform-origin: center; } to { opacity: 1; transform: scale(1.12); transform-origin: center; } } | |
| } | |
| </style> | |
| <script> | |
| (function () { | |
| const root = document.getElementById("alphago-move-37"); | |
| const svg = root.querySelector(".move37-board"); | |
| const ns = "http://www.w3.org/2000/svg"; | |
| const moves = [ | |
| ["B","pd"],["W","dp"],["B","cd"],["W","qp"],["B","op"],["W","oq"],["B","nq"],["W","pq"],["B","cn"],["W","fq"], | |
| ["B","mp"],["W","qn"],["B","ic"],["W","dj"],["B","po"],["W","qo"],["B","cp"],["W","cq"],["B","bq"],["W","co"], | |
| ["B","bp"],["W","bo"],["B","do"],["W","bn"],["B","dq"],["W","ep"],["B","dr"],["W","cm"],["B","jp"],["W","cg"], | |
| ["B","ed"],["W","qf"],["B","qe"],["W","pf"],["B","nd"],["W","pi"],["B","oj"],["W","oi"],["B","nj"],["W","mh"], | |
| ["B","gp"],["W","gq"],["B","dn"],["W","dm"],["B","fo"],["W","hp"],["B","ho"],["W","eo"],["B","en"],["W","fn"] | |
| ]; | |
| const letters = "ABCDEFGHJKLMNOPQRST"; | |
| const grid = svg.querySelector('[data-layer="grid"]'); | |
| const stars = svg.querySelector('[data-layer="stars"]'); | |
| const coords = svg.querySelector('[data-layer="coordinates"]'); | |
| const stones = svg.querySelector('[data-layer="stones"]'); | |
| const highlight = svg.querySelector('[data-layer="highlight"]'); | |
| const range = root.querySelector("#move37-range"); | |
| const moveNumber = root.querySelector('[data-role="move-number"]'); | |
| const kicker = root.querySelector('[data-role="kicker"]'); | |
| const headline = root.querySelector('[data-role="headline"]'); | |
| const detail = root.querySelector('[data-role="detail"]'); | |
| const margin = 50; | |
| const step = 30; | |
| let current = 0; | |
| let timer = null; | |
| function add(tag, attrs, parent) { | |
| const element = document.createElementNS(ns, tag); | |
| Object.entries(attrs).forEach(function (entry) { element.setAttribute(entry[0], entry[1]); }); | |
| parent.appendChild(element); | |
| return element; | |
| } | |
| for (let i = 0; i < 19; i += 1) { | |
| const p = margin + i * step; | |
| add("line", { x1: margin, y1: p, x2: margin + 18 * step, y2: p, class: "board-line" }, grid); | |
| add("line", { x1: p, y1: margin, x2: p, y2: margin + 18 * step, class: "board-line" }, grid); | |
| const top = add("text", { x: p, y: 32, class: "coord" }, coords); | |
| top.textContent = letters[i]; | |
| const left = add("text", { x: 30, y: p, class: "coord" }, coords); | |
| left.textContent = String(19 - i); | |
| } | |
| [3, 9, 15].forEach(function (x) { | |
| [3, 9, 15].forEach(function (y) { | |
| add("circle", { cx: margin + x * step, cy: margin + y * step, r: 4, class: "star" }, stars); | |
| }); | |
| }); | |
| function point(sgf) { | |
| return { x: margin + (sgf.charCodeAt(0) - 97) * step, y: margin + (sgf.charCodeAt(1) - 97) * step }; | |
| } | |
| function humanCoord(sgf) { | |
| const col = letters[sgf.charCodeAt(0) - 97]; | |
| return col + String(19 - (sgf.charCodeAt(1) - 97)); | |
| } | |
| function render() { | |
| stones.replaceChildren(); | |
| highlight.replaceChildren(); | |
| const occupied = new Map(); | |
| moves.slice(0, current).forEach(function (move, index) { | |
| occupied.set(move[1], { color: move[0], number: index + 1 }); | |
| }); | |
| occupied.forEach(function (stone, key) { | |
| const p = point(key); | |
| add("circle", { cx: p.x, cy: p.y, r: 13.2, fill: stone.color === "B" ? "url(#move37-black)" : "url(#move37-white)", class: "stone" }, stones); | |
| const number = add("text", { x: p.x, y: p.y + 0.5, fill: stone.color === "B" ? "#ffffff" : "#111111", class: "stone-number" }, stones); | |
| number.textContent = String(stone.number); | |
| }); | |
| if (current > 0) { | |
| const last = moves[current - 1]; | |
| const p = point(last[1]); | |
| add("circle", { cx: p.x, cy: p.y, r: 16.8, class: current === 37 ? "move37-pulse" : "move37-ring" }, highlight); | |
| kicker.textContent = last[0] === "B" ? "AlphaGo · Black" : "Lee Sedol · White"; | |
| headline.textContent = "Move " + current + " · " + humanCoord(last[1]); | |
| if (current === 37) { | |
| detail.textContent = "The famous fifth-line shoulder hit. It looked unnatural to professionals, yet connected influence across the right side and center."; | |
| const label = add("text", { x: p.x, y: p.y - 28, class: "move37-label" }, highlight); | |
| label.textContent = "MOVE 37"; | |
| } else if (current === 36) { | |
| detail.textContent = "Pause here: the conventional-looking position just before AlphaGo's surprise."; | |
| } else if (current === 38) { | |
| detail.textContent = "Lee responds at O11 after taking unusually long to assess the unexpected shoulder hit."; | |
| } else { | |
| detail.textContent = current < 37 ? "The opening develops toward the position that made Move 37 so surprising." : "The game continues as AlphaGo converts its unconventional influence into a playable whole-board strategy."; | |
| } | |
| } else { | |
| kicker.textContent = "Opening position"; | |
| headline.textContent = "Move 0 of 50"; | |
| detail.textContent = "AlphaGo plays Black. Lee Sedol plays White."; | |
| } | |
| moveNumber.textContent = String(current); | |
| range.value = String(current); | |
| } | |
| function stop() { | |
| if (timer) { clearInterval(timer); timer = null; } | |
| const play = root.querySelector('[data-action="play"]'); | |
| play.innerHTML = '<i data-lucide="play" aria-hidden="true"></i> Play'; | |
| if (window.lucide) { lucide.createIcons({ attrs: { width: 16, height: 16 } }); } | |
| } | |
| function setMove(value) { | |
| current = Math.max(0, Math.min(moves.length, value)); | |
| render(); | |
| } | |
| root.querySelector('[data-action="start"]').addEventListener("click", function () { stop(); setMove(0); }); | |
| root.querySelector('[data-action="previous"]').addEventListener("click", function () { stop(); setMove(current - 1); }); | |
| root.querySelector('[data-action="next"]').addEventListener("click", function () { stop(); setMove(current + 1); }); | |
| root.querySelector('[data-action="move37"]').addEventListener("click", function () { stop(); setMove(37); }); | |
| root.querySelector('[data-action="play"]').addEventListener("click", function (event) { | |
| if (timer) { stop(); return; } | |
| if (current >= moves.length) { setMove(0); } | |
| event.currentTarget.innerHTML = '<i data-lucide="pause" aria-hidden="true"></i> Pause'; | |
| if (window.lucide) { lucide.createIcons({ attrs: { width: 16, height: 16 } }); } | |
| timer = setInterval(function () { | |
| if (current >= moves.length) { stop(); return; } | |
| setMove(current + 1); | |
| if (current === 37) { stop(); } | |
| }, 520); | |
| }); | |
| range.addEventListener("input", function () { stop(); setMove(Number(range.value)); }); | |
| render(); | |
| }()); | |
| </script> | |
| <script id="codex-visualization-floating-ui-core" src="https://unpkg.com/@floating-ui/core@1.7.3/dist/floating-ui.core.umd.min.js"></script> | |
| <script id="codex-visualization-floating-ui-dom" src="https://unpkg.com/@floating-ui/dom@1.7.4/dist/floating-ui.dom.umd.min.js"></script> | |
| <script id="codex-visualization-lucide" async src="https://unpkg.com/lucide@1.17.0/dist/umd/lucide.js"></script> | |
| <script id="codex-visualization-tooltip">/* oxlint-disable typescript/no-unsafe-argument, typescript/no-unsafe-call, typescript/no-unsafe-return */ | |
| // Runs inside the visualization sandbox, not the host webview. | |
| (() => { | |
| if (window.FloatingUIDOM == null) { | |
| return; | |
| } | |
| const { autoUpdate, computePosition, flip, offset, shift, size } = | |
| window.FloatingUIDOM; | |
| const tooltipPlacements = new Set(["top", "right", "bottom", "left"]); | |
| const tooltipId = `codex-visualization-tooltip-${ | |
| window.crypto?.randomUUID?.() ?? Date.now().toString(36) | |
| }`; | |
| const tooltipGap = 5; | |
| const hoverDelay = 700; | |
| const skipDelay = 300; | |
| let activeTrigger = null; | |
| let pendingTrigger = null; | |
| let tooltip = null; | |
| let openTimeout = null; | |
| let autoUpdateCleanup = null; | |
| let positionRequest = 0; | |
| let skipDelayUntil = 0; | |
| const getTrigger = (target) => | |
| target?.nodeType === Node.ELEMENT_NODE | |
| ? target.closest("[data-tooltip]") | |
| : null; | |
| const containsTarget = (trigger, target) => | |
| target?.nodeType != null && trigger.contains(target); | |
| const getContent = (trigger) => | |
| trigger.getAttribute("data-tooltip")?.trim() ?? ""; | |
| const getPlacement = (trigger) => { | |
| const placement = trigger.getAttribute("data-tooltip-placement"); | |
| return tooltipPlacements.has(placement) ? placement : "top"; | |
| }; | |
| const getTooltip = () => { | |
| if (tooltip == null) { | |
| tooltip = document.createElement("div"); | |
| tooltip.id = tooltipId; | |
| tooltip.className = "tooltip"; | |
| tooltip.setAttribute("role", "tooltip"); | |
| } | |
| return tooltip; | |
| }; | |
| const setDescribedBy = (trigger, described) => { | |
| const ids = new Set( | |
| (trigger.getAttribute("aria-describedby") ?? "") | |
| .split(/\s+/) | |
| .filter(Boolean), | |
| ); | |
| if (described) { | |
| ids.add(tooltipId); | |
| } else { | |
| ids.delete(tooltipId); | |
| } | |
| if (ids.size === 0) { | |
| trigger.removeAttribute("aria-describedby"); | |
| } else { | |
| trigger.setAttribute("aria-describedby", [...ids].join(" ")); | |
| } | |
| }; | |
| const clearOpenTimeout = () => { | |
| if (openTimeout != null) { | |
| window.clearTimeout(openTimeout); | |
| openTimeout = null; | |
| } | |
| pendingTrigger = null; | |
| }; | |
| const closeTooltip = (activateSkipDelay = true) => { | |
| clearOpenTimeout(); | |
| positionRequest += 1; | |
| autoUpdateCleanup?.(); | |
| autoUpdateCleanup = null; | |
| if (activeTrigger == null) { | |
| return; | |
| } | |
| setDescribedBy(activeTrigger, false); | |
| activeTrigger = null; | |
| tooltip?.remove(); | |
| if (activateSkipDelay) { | |
| skipDelayUntil = Date.now() + skipDelay; | |
| } | |
| }; | |
| const updatePosition = (trigger, floating) => { | |
| const request = ++positionRequest; | |
| void computePosition(trigger, floating, { | |
| middleware: [ | |
| offset(tooltipGap), | |
| flip({ padding: tooltipGap }), | |
| shift({ padding: tooltipGap }), | |
| size({ | |
| padding: tooltipGap, | |
| apply({ availableHeight, availableWidth, elements }) { | |
| elements.floating.style.setProperty( | |
| "--tooltip-available-width", | |
| `${Math.max(0, availableWidth)}px`, | |
| ); | |
| elements.floating.style.setProperty( | |
| "--tooltip-available-height", | |
| `${Math.max(0, availableHeight)}px`, | |
| ); | |
| }, | |
| }), | |
| ], | |
| placement: getPlacement(trigger), | |
| strategy: "fixed", | |
| }) | |
| .then(({ x, y }) => { | |
| if (activeTrigger !== trigger || request !== positionRequest) { | |
| return; | |
| } | |
| const scale = window.devicePixelRatio || 1; | |
| floating.style.transform = `translate(${Math.round(x * scale) / scale}px, ${Math.round(y * scale) / scale}px)`; | |
| floating.style.visibility = "visible"; | |
| }) | |
| .catch(() => { | |
| if (activeTrigger === trigger && request === positionRequest) { | |
| closeTooltip(false); | |
| } | |
| }); | |
| }; | |
| const openTooltip = (trigger) => { | |
| const content = getContent(trigger); | |
| if (!trigger.isConnected || content.length === 0) { | |
| return; | |
| } | |
| clearOpenTimeout(); | |
| if (activeTrigger === trigger) { | |
| return; | |
| } | |
| closeTooltip(); | |
| const floating = getTooltip(); | |
| floating.textContent = content; | |
| floating.style.visibility = "hidden"; | |
| floating.style.transform = "translate(0, 0)"; | |
| document.body.appendChild(floating); | |
| activeTrigger = trigger; | |
| setDescribedBy(trigger, true); | |
| autoUpdateCleanup = autoUpdate(trigger, floating, () => { | |
| updatePosition(trigger, floating); | |
| }); | |
| }; | |
| const requestOpen = (trigger, immediate = false) => { | |
| if ( | |
| getContent(trigger).length === 0 || | |
| activeTrigger === trigger || | |
| pendingTrigger === trigger | |
| ) { | |
| return; | |
| } | |
| clearOpenTimeout(); | |
| pendingTrigger = trigger; | |
| const delay = | |
| immediate || activeTrigger != null || Date.now() < skipDelayUntil | |
| ? 0 | |
| : hoverDelay; | |
| if (delay === 0) { | |
| openTooltip(trigger); | |
| return; | |
| } | |
| openTimeout = window.setTimeout(() => { | |
| openTimeout = null; | |
| pendingTrigger = null; | |
| openTooltip(trigger); | |
| }, delay); | |
| }; | |
| const handlePointerOpen = (event) => { | |
| if (event.pointerType === "touch") { | |
| return; | |
| } | |
| const trigger = getTrigger(event.target); | |
| if (trigger == null || containsTarget(trigger, event.relatedTarget)) { | |
| return; | |
| } | |
| requestOpen(trigger); | |
| }; | |
| const handleLeave = (event) => { | |
| const trigger = getTrigger(event.target); | |
| if (trigger == null || containsTarget(trigger, event.relatedTarget)) { | |
| return; | |
| } | |
| if (activeTrigger === trigger || pendingTrigger === trigger) { | |
| closeTooltip(); | |
| } | |
| }; | |
| const handleFocusIn = (event) => { | |
| const trigger = getTrigger(event.target); | |
| if (trigger?.matches(":focus-visible")) { | |
| requestOpen(trigger, true); | |
| } | |
| }; | |
| const handleKeyDown = (event) => { | |
| if (event.key === "Escape") { | |
| closeTooltip(); | |
| } | |
| }; | |
| const handleContextMenu = (event) => { | |
| const trigger = getTrigger(event.target); | |
| if (activeTrigger === trigger || pendingTrigger === trigger) { | |
| closeTooltip(); | |
| } | |
| }; | |
| const destroy = () => { | |
| closeTooltip(false); | |
| document.removeEventListener("pointerover", handlePointerOpen); | |
| document.removeEventListener("pointerout", handleLeave); | |
| document.removeEventListener("focusin", handleFocusIn); | |
| document.removeEventListener("focusout", handleLeave); | |
| document.removeEventListener("keydown", handleKeyDown); | |
| document.removeEventListener("contextmenu", handleContextMenu); | |
| tooltip = null; | |
| }; | |
| document.addEventListener("pointerover", handlePointerOpen); | |
| document.addEventListener("pointerout", handleLeave); | |
| document.addEventListener("focusin", handleFocusIn); | |
| document.addEventListener("focusout", handleLeave); | |
| document.addEventListener("keydown", handleKeyDown); | |
| document.addEventListener("contextmenu", handleContextMenu); | |
| window.addEventListener("pagehide", destroy, { once: true }); | |
| })(); | |
| </script> | |
| <script id="codex-visualization-lucide-initialization">(() => { | |
| const initialize = () => { | |
| globalThis.lucide?.createIcons({ attrs: { width: 16, height: 16 } }); | |
| }; | |
| if (globalThis.lucide != null) { | |
| initialize(); | |
| return; | |
| } | |
| document | |
| .getElementById("codex-visualization-lucide") | |
| ?.addEventListener("load", initialize, { once: true }); | |
| })(); | |
| </script> | |
| </body> | |
| </html> | |