diff --git a/assets/inject/dream-skin.css b/assets/inject/dream-skin.css index 350528d..aaafc8e 100644 --- a/assets/inject/dream-skin.css +++ b/assets/inject/dream-skin.css @@ -189,7 +189,7 @@ html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(. html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) article, html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) .message, -html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="surface"] { +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="surface"]:not(:is(.composer-surface-chrome, .dream-skin-composer, .dream-skin-composer-dock, .dream-skin-composer-dock *)) { border: 1px solid color-mix(in srgb, var(--ds-text) 7%, transparent) !important; background: color-mix(in srgb, var(--ds-panel) 96%, transparent) !important; box-shadow: 0 10px 28px var(--ds-ink-shadow); @@ -217,6 +217,37 @@ html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface) > hea backdrop-filter: none !important; } +html.codex-dream-skin :is( + header.app-header-tint, + [class*="_AppHeader_"], + [class*="_TitleBar_"], + [class*="_Titlebar_"], + [class*="_TopBar_"] +) { + background: + linear-gradient(90deg, + color-mix(in srgb, var(--ds-panel) 88%, transparent), + color-mix(in srgb, var(--ds-panel-2) 84%, transparent), + color-mix(in srgb, var(--ds-lime) 10%, var(--ds-panel-2))) !important; + border-color: color-mix(in srgb, var(--ds-text) 8%, transparent) !important; + color: color-mix(in srgb, var(--ds-text) 88%, var(--ds-muted)) !important; + box-shadow: 0 1px 0 color-mix(in srgb, white 42%, transparent) inset !important; + backdrop-filter: blur(18px) saturate(112%) !important; +} + +html.codex-dream-skin :is( + header.app-header-tint, + [class*="_AppHeader_"], + [class*="_TitleBar_"], + [class*="_Titlebar_"], + [class*="_TopBar_"] +) :where(button, [role="button"]) { + color: color-mix(in srgb, var(--ds-text) 78%, var(--ds-muted)) !important; + background: color-mix(in srgb, var(--ds-panel) 56%, transparent) !important; + border-color: color-mix(in srgb, var(--ds-text) 8%, transparent) !important; + box-shadow: none !important; +} + /* ------------------------------------------------------- decoration layer */ #codex-dream-skin-chrome { @@ -227,6 +258,273 @@ html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface) > hea border-radius: 24px 0 0 0; } +.dream-skin-home-dog-backdrop { display: none; } + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-home-dog-backdrop { + position: absolute !important; + z-index: 2 !important; + right: auto !important; + display: none !important; + object-fit: cover !important; + object-position: center 42% !important; + opacity: 1 !important; + filter: saturate(112%) contrast(103%) !important; + transform: none !important; + -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 7%, #000 88%, transparent 100%) !important; + mask-image: linear-gradient(to bottom, transparent 0, #000 7%, #000 88%, transparent 100%) !important; + pointer-events: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-happy-home-canvas { + position: relative !important; + isolation: isolate !important; + overflow: hidden !important; + scrollbar-gutter: auto !important; + background: var(--dog-paper) !important; +} + +/* With a workspace wallpaper active, the legacy hero-art layers (a full-canvas + and the faint ghost pseudo) would paint a second, differently-scaled + copy of the artwork on top and read as a visible seam. Let the wallpaper + carry the whole home surface instead. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-wallpaper="true"] .dream-skin-happy-home-canvas > .dream-skin-native-home-dog { + display: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-wallpaper="true"] main.dream-skin-home-shell::before { + content: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-wallpaper="true"] main.dream-skin-home-shell { + background: + var(--dream-skin-wallpaper) var(--ds-wallpaper-position) / cover no-repeat, + var(--dog-paper) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-wallpaper="true"] .dream-skin-happy-home-canvas { + background: transparent !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class*="_MainContentTopFade_"] { + display: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell header.app-header-tint { + background: transparent !important; + border-bottom: none !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class*="_MainContentViewport_"], +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class*="_MainContentViewport_"]::before, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class*="_MainContentViewport_"]::after, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell::before, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell::after, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class~="draggable"][class*="grid-cols-"], +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class*="_MainContentViewport_"] [class*="contain:layout_paint"] { + background: transparent !important; + border-bottom: none !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-happy-home-canvas > .dream-skin-native-home-dog { + position: absolute !important; + z-index: 0 !important; + inset: 0 !important; + display: block !important; + width: 100% !important; + height: 100% !important; + object-fit: cover !important; + object-position: center !important; + opacity: 1 !important; + filter: saturate(112%) contrast(103%) !important; + pointer-events: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-happy-home-canvas > :not(.dream-skin-native-home-dog) { + position: relative !important; + z-index: 2 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-happy-home-canvas > div, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-happy-home-canvas > div > div { + background-color: transparent !important; + background-image: none !important; +} + +@media (max-width: 1180px) { + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-home-dog-backdrop { + opacity: 1 !important; + } +} + +/* Opaque poster foreground composed around the full-color dog artwork. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-title { + position: relative !important; + z-index: 4 !important; + width: min(650px, calc(100vw - 80px)) !important; + margin-inline: auto !important; + padding: 13px 24px 15px !important; + border: 4px solid var(--dog-ink) !important; + border-radius: 20px 12px 22px 14px !important; + background: + repeating-linear-gradient(2deg, rgba(255,255,255,.14) 0 2px, transparent 2px 9px), + var(--dog-yellow) !important; + color: var(--dog-ink) !important; + box-shadow: 8px 8px 0 var(--dog-ink) !important; + font-family: ui-rounded, "SF Pro Rounded", "PingFang SC", system-ui, sans-serif !important; + font-weight: 950 !important; + text-align: center !important; + transform: translateX(clamp(-280px, -15vw, -110px)) rotate(-.7deg) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-title::before { + content: "HAPPY CODING!" !important; + position: absolute !important; + left: 18px !important; + top: -24px !important; + padding: 4px 10px !important; + border: 3px solid var(--dog-ink) !important; + border-radius: 999px 850px 999px 900px !important; + background: #8eddea !important; + box-shadow: 3px 3px 0 var(--dog-ink) !important; + font-size: 10px !important; + letter-spacing: .12em !important; + transform: rotate(-4deg) !important; +} + +/* Pink washi tape holding the title card's top-right corner. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-title::after { + content: "" !important; + position: absolute !important; + top: -13px !important; + right: 46px !important; + width: 88px !important; + height: 24px !important; + background: + repeating-linear-gradient(90deg, rgba(255,255,255,.4) 0 7px, rgba(255,255,255,.12) 7px 14px), + #f58bb7 !important; + opacity: .88 !important; + transform: rotate(4.5deg) !important; + box-shadow: 0 2px 3px rgba(32, 32, 29, .18) !important; + pointer-events: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions { + position: relative !important; + z-index: 4 !important; + width: min(720px, calc(100vw - 70px)) !important; + margin-inline: auto !important; + transform: translateX(clamp(-280px, -15vw, -110px)) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions button { + background-image: repeating-linear-gradient(3deg, rgba(255,255,255,.12) 0 2px, transparent 2px 9px) !important; + opacity: 1 !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions .grid > :nth-child(1) > button { background-color: #67d1df !important; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions .grid > :nth-child(2) > button { background-color: #91d14b !important; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions .grid > :nth-child(3) > button { background-color: #ff6857 !important; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions .grid > :nth-child(4) > button { background-color: #ffd84a !important; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions .grid > :nth-child(1) > button span:has(> svg) { background-color: #ffd84a !important; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions .grid > :nth-child(2) > button span:has(> svg) { background-color: #fffaf0 !important; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions .grid > :nth-child(3) > button span:has(> svg) { background-color: #ffd84a !important; } + +/* Plan B: quote text centered in the card, star coin pinned to the left edge like a sticker. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-title { + align-items: center !important; +} +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-title > div:first-child { + align-items: center !important; +} +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-title .size-14 { + position: absolute !important; + left: -32px !important; + top: 50% !important; + transform: translateY(-50%) rotate(-10deg) !important; + opacity: 1 !important; +} + +/* Squiggle hugs the quote text: painted on the heading itself, width follows the text. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-title .heading-xl { + padding-bottom: 13px !important; + background: + url('data:image/svg+xml;utf8,') center bottom / 100% 11px no-repeat !important; +} + +/* Doodles floating in the gap between the title card and the suggestion cards. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions::before { + content: "" !important; + position: absolute !important; + top: -34px !important; + left: -6px !important; + width: 30px !important; + height: 30px !important; + background: url('data:image/svg+xml;utf8,') center / contain no-repeat !important; + transform: rotate(-14deg) !important; + pointer-events: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions::after { + content: "" !important; + position: absolute !important; + top: -30px !important; + right: 6px !important; + width: 26px !important; + height: 26px !important; + background: url('data:image/svg+xml;utf8,') center / contain no-repeat !important; + transform: rotate(10deg) !important; + pointer-events: none !important; +} +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-card-1 { background-color: #ffd84a !important; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-card-2 { background-color: #67d1df !important; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-card-3 { background-color: #91d14b !important; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-card-4 { background-color: #ff6857 !important; } + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-home-voice { + position: relative !important; + z-index: 5 !important; + border: 3px solid var(--dog-ink) !important; + border-radius: 16px 10px 18px 12px !important; + background: + repeating-linear-gradient(2deg, rgba(255,255,255,.15) 0 2px, transparent 2px 8px), + #8eddea !important; + color: var(--dog-ink) !important; + box-shadow: 6px 6px 0 var(--dog-ink) !important; + opacity: 1 !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell div:has(> .horizontal-scroll-fade-mask .group\/project-selector) { + position: relative !important; + z-index: 5 !important; + background-color: #67d1df !important; + opacity: 1 !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .composer-surface-chrome { + position: relative !important; + z-index: 6 !important; + background: + linear-gradient(90deg, #ff6857 0 10px, transparent 10px), + repeating-linear-gradient(3deg, rgba(255,216,74,.13) 0 2px, transparent 2px 9px), + #fff8df !important; + opacity: 1 !important; + backdrop-filter: none !important; +} + +@media (max-width: 1180px) { + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell :where( + .dream-skin-happy-home-title, + .group\/home-suggestions + ) { + transform: translateX(-6vw) !important; + } +} + .dream-skin-brand { position: absolute; left: 23px; @@ -272,6 +570,57 @@ html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface) > hea .dream-skin-status i { width: 7px; height: 7px; border-radius: 50%; background: var(--ds-green); box-shadow: 0 0 10px var(--ds-green); } #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-status { display: flex; } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-brand { + top: 5px !important; + /* Clear the native titlebar buttons (sidebar toggle / back / forward span x363-455). */ + left: 195px !important; + padding: 7px 15px 7px 8px !important; + background: var(--dog-cream) !important; + border: 3px solid var(--dog-coral) !important; + border-radius: 999px !important; + box-shadow: 4px 4px 0 var(--dog-purple) !important; + transform: rotate(-.6deg) !important; +} + +/* Chip shows only the subtitle: hide the bilingual theme name line. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-brand b { + display: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-brand small { + margin-top: 0 !important; + color: var(--dog-ink) !important; + font-size: 13px !important; + font-weight: 900 !important; + letter-spacing: .1em !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-brand .dream-skin-portal-mark { + border: 2px solid var(--dog-ink) !important; + background: var(--dog-yellow) !important; + color: var(--dog-coral) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-brand :where(b, small) { + color: var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-status { + top: 10px !important; + padding: 6px 12px !important; + background: var(--dog-yellow) !important; + border: 2px solid var(--dog-ink) !important; + color: var(--dog-ink) !important; + box-shadow: 3px 3px 0 var(--dog-purple) !important; + transform: rotate(.7deg) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-status i { + background: var(--dog-coral) !important; + box-shadow: 0 0 0 2px var(--dog-cream) !important; +} + .dream-skin-quote { position: absolute; right: 28px; @@ -366,6 +715,23 @@ html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface) > hea font: italic 9px/1.2 "Snell Roundhand", "Segoe Print", "Comic Sans MS", cursive; letter-spacing: .04em; } +#codex-dream-skin-chrome:not(.dream-skin-home-shell) .dream-skin-composer-stamp { + left: 28px; + right: auto; + bottom: 74px; + display: flex; + padding: 5px 5px 7px; + opacity: .92; + transform: rotate(-4deg); +} +#codex-dream-skin-chrome:not(.dream-skin-home-shell) .dream-skin-composer-stamp img { + width: 46px; + height: 46px; +} +#codex-dream-skin-chrome:not(.dream-skin-home-shell) .dream-skin-composer-stamp span { + max-width: 64px; + font-size: 8px; +} /* Corner stickers. */ .dream-skin-corner { @@ -694,6 +1060,25 @@ html.codex-dream-skin :is(.composer-surface-chrome, .dream-skin-composer) { overflow: visible !important; } +/* The unified Codex shell splits its composer into a full-width Body and a + narrower Footer. Theme the Body as the single surface and keep the Footer + structural, otherwise width rules create a second card inside the dock. */ +html.codex-dream-skin .dream-skin-composer[class*="_ComposerLayoutBody_"] { + width: 100% !important; + max-width: none !important; + margin-inline: 0 !important; +} + +html.codex-dream-skin .dream-skin-composer[class*="_ComposerLayoutBody_"] + [class*="_ComposerLayoutFooter_"] { + border-color: transparent !important; + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + box-shadow: none !important; + backdrop-filter: none !important; +} + html.codex-dream-skin :is(.composer-surface-chrome, .dream-skin-composer)::before { content: "✦"; position: absolute; @@ -712,6 +1097,54 @@ html.codex-dream-skin :is(.composer-surface-chrome, .dream-skin-composer)::befor font-size: 13px; } +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) .dream-skin-composer-dock:not(.dream-skin-composer) { + border-color: transparent !important; + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + box-shadow: none !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + :where([class*="_ComposerLayoutRoot_"], .dream-skin-composer-dock:not(.dream-skin-composer)) { + --composer-background: transparent; + --composer-surface-background: transparent; + --composer-surface-primary: transparent; + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + box-shadow: none !important; + border-color: transparent !important; +} + +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + :where([class*="_ComposerLayoutRoot_"], .dream-skin-composer-dock:not(.dream-skin-composer)) + > :not(.composer-surface-chrome):not(.dream-skin-composer) { + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + box-shadow: none !important; + border-color: transparent !important; +} + +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock, +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock::before, +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock::after { + border-color: transparent !important; + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + box-shadow: none !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock::before, +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock::after { + content: none !important; + display: none !important; +} + .dream-skin-home div:has(> .horizontal-scroll-fade-mask .group\/project-selector) { position: relative; padding-top: 28px !important; @@ -786,6 +1219,108 @@ html.codex-dream-skin [data-message-author-role] { border-radius: 18px; } .dream-skin-home .group\/home-suggestions button > span:last-child::after { display: none; } } +/* Dynamically tagged review chrome: the app does not expose stable class names here. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-review-toolbar { + box-sizing: border-box !important; + min-height: 48px !important; + padding: 5px 10px !important; + gap: 10px !important; + border: 0 !important; + border-bottom: 3px solid var(--dog-marker-shadow) !important; + background: + repeating-linear-gradient(2deg, rgba(255,255,255,.14) 0 2px, transparent 2px 8px), + linear-gradient(94deg, #ffd84b 0 28%, #8eddea 28% 55%, #9ad85d 55% 78%, #ff6a58 78%) !important; + box-shadow: inset 0 -2px 0 rgba(255,255,255,.38) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-review-tab { + min-height: 34px !important; + padding: 5px 34px 5px 13px !important; + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 8px 11px 7px 10px !important; + background: var(--dog-marker-cream) !important; + color: var(--dog-marker-shadow) !important; + box-shadow: 3px 3px 0 var(--dog-marker-red) !important; + font-weight: 900 !important; + transform: rotate(-.25deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + .dream-skin-review-close, + .dream-skin-review-add, + .dream-skin-review-action +) { + min-width: 29px !important; + min-height: 29px !important; + margin-inline: 3px !important; + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 8px 6px 9px 7px !important; + color: var(--dog-marker-shadow) !important; + box-shadow: 2px 2px 0 var(--dog-marker-shadow) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-review-close { + background: var(--dog-marker-red) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-review-add { + background: var(--dog-marker-green) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-review-action { + background: var(--dog-marker-yellow) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + .dream-skin-review-close, + .dream-skin-review-add, + .dream-skin-review-action +):hover { + transform: translate(1px, 1px) rotate(-2deg) !important; + box-shadow: 1px 1px 0 var(--dog-marker-shadow) !important; +} + +/* Compact dog stamp while review squeezes the conversation pane; reveal the copy on hover. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-thread-narrow="true"] .dream-skin-composer-stamp { + left: 10px !important; + bottom: 168px !important; + width: 62px !important; + padding: 5px !important; + gap: 2px !important; + pointer-events: auto !important; + cursor: pointer !important; + transform: rotate(-4deg) !important; + transform-origin: left bottom !important; + transition: width .18s ease, transform .18s ease, bottom .18s ease !important; + z-index: 48 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-thread-narrow="true"] .dream-skin-composer-stamp img { + width: 50px !important; + height: 50px !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-thread-narrow="true"] .dream-skin-composer-stamp span { + display: block !important; + width: 0 !important; + max-height: 0 !important; + opacity: 0 !important; + overflow: hidden !important; + transition: width .18s ease, max-height .18s ease, opacity .14s ease !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-thread-narrow="true"] .dream-skin-composer-stamp:hover { + bottom: 174px !important; + width: 132px !important; + transform: rotate(-2deg) translateY(-3px) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-thread-narrow="true"] .dream-skin-composer-stamp:hover span { + width: 68px !important; + max-height: 38px !important; + opacity: 1 !important; +} + @media (prefers-reduced-motion: reduce) { .dream-skin-particles i { animation: none !important; } } @@ -1527,6 +2062,125 @@ html.codex-dream-skin[data-dream-theme="moonlit-immortal"] [data-radix-popper-co } } +/* Happy Coding Dog — acrylic marker material pass ------------------------- */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] { + --dog-marker-red: #f04f3d; + --dog-marker-blue: #176fa8; + --dog-marker-green: #78c64b; + --dog-marker-yellow: #ffd84a; + --dog-marker-cream: #fff3c8; + --dog-marker-shadow: #20201d; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel { + background: + linear-gradient(88deg, transparent 0 94%, rgba(5, 94, 113, .18) 94% 100%), + repeating-linear-gradient(2deg, rgba(255, 255, 255, .075) 0 2px, transparent 2px 9px), + var(--dog-cyan) !important; + border-right: 3px solid var(--dog-marker-shadow) !important; + box-shadow: 5px 0 0 rgba(32, 32, 29, .13) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel :where( + [aria-current="page"], + [data-state="active"], + [data-selected="true"] +) { + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 10px 7px 11px 8px !important; + background: + repeating-linear-gradient(-4deg, rgba(255,255,255,.12) 0 2px, transparent 2px 8px), + var(--dog-marker-yellow) !important; + box-shadow: 4px 4px 0 var(--dog-marker-shadow) !important; + transform: rotate(-.25deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-message-author-role="user"] { + border: 3px solid var(--dog-marker-shadow) !important; + border-radius: 17px 12px 16px 10px !important; + background: + repeating-linear-gradient(5deg, rgba(255,255,255,.11) 0 2px, transparent 2px 9px), + color-mix(in srgb, var(--dog-marker-yellow) 34%, var(--dog-marker-cream)) !important; + box-shadow: 5px 5px 0 var(--dog-marker-red) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + [data-testid*="tool"], + [data-testid*="diff"], + [class*="ToolCall"], + [class*="DiffCard"] +) { + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 12px 8px 13px 9px !important; + background: + linear-gradient(90deg, var(--dog-marker-blue) 0 9px, transparent 9px), + repeating-linear-gradient(-3deg, rgba(23,111,168,.045) 0 2px, transparent 2px 8px), + #fffaf0 !important; + box-shadow: 5px 5px 0 rgba(32, 32, 29, .92) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + [data-testid*="tool"], + [class*="ToolCall"] +):nth-of-type(3n + 2) { + background: + linear-gradient(90deg, var(--dog-marker-green) 0 9px, transparent 9px), + repeating-linear-gradient(3deg, rgba(120,198,75,.055) 0 2px, transparent 2px 9px), + #fffaf0 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(pre, [data-testid*="code"]):not(code) { + border: 3px solid var(--dog-marker-shadow) !important; + border-radius: 11px 8px 13px 9px !important; + background: + repeating-linear-gradient(4deg, rgba(255,255,255,.035) 0 2px, transparent 2px 9px), + #123f67 !important; + color: #fff8df !important; + box-shadow: 6px 6px 0 var(--dog-marker-shadow) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(code):not(pre code) { + border: 1.5px solid var(--dog-marker-shadow) !important; + border-radius: 6px 4px 7px 5px !important; + background: color-mix(in srgb, var(--dog-marker-green) 27%, #fffaf0) !important; + color: var(--dog-marker-shadow) !important; + box-shadow: 2px 2px 0 rgba(32,32,29,.28) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class~="rounded-3xl"][class~="bg-surface-elevated-secondary"] { + border: 3px solid var(--dog-marker-shadow) !important; + border-radius: 15px 10px 16px 11px !important; + background: + linear-gradient(to bottom, var(--dog-marker-green) 0 39px, transparent 39px), + repeating-linear-gradient(-3deg, rgba(32,32,29,.025) 0 1px, transparent 1px 8px), + #fffaf0 !important; + box-shadow: 7px 7px 0 var(--dog-marker-shadow) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + .composer-surface-chrome, + .dream-skin-composer, + [data-testid="composer"] +) { + border-width: 3px !important; + border-color: var(--dog-marker-shadow) !important; + border-radius: 17px 12px 18px 13px !important; + background: + repeating-linear-gradient(3deg, rgba(255,216,74,.09) 0 2px, transparent 2px 9px), + #fffaf0 !important; + box-shadow: 7px 7px 0 var(--dog-marker-shadow) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(button, [role="button"]):not([disabled]):hover { + filter: saturate(1.08) contrast(1.02) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(h1, h2, h3, strong) { + text-decoration-color: var(--dog-marker-red) !important; + text-decoration-thickness: 3px !important; + text-underline-offset: 4px !important; +} + @media (max-width: 680px) { html.codex-dream-skin[data-dream-theme="moonlit-immortal"] body { background-position: 74% 18% !important; @@ -1591,6 +2245,10 @@ html.codex-dream-skin--minimal-focus .dream-skin-corner, html.codex-dream-skin--minimal-focus .dream-skin-washi, html.codex-dream-skin--minimal-focus .dream-skin-composer-stamp { display: none !important; } +#codex-dream-skin-chrome:not(.dream-skin-home-shell) .dream-skin-composer-stamp { + display: flex !important; +} + html.codex-dream-skin--minimal-focus .dream-skin-home > div:first-child > div:first-child > div:first-child > div:first-child > div:first-child { width: 78% !important; } @@ -3434,1166 +4092,3258 @@ html.codex-dream-skin[data-dream-theme="potion-workshop"] :is(main.main-surface, /* ----------------------------------------------------------- focus capybara */ -html.codex-dream-skin[data-dream-theme="focus-capybara"] body { - background: #f7f4ee !important; +/* -------------------------------------------------------- happy coding dog */ + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] { + --dog-ink: #20201d; + --dog-paper: #fff5d8; + --dog-cream: #fffaf0; + --dog-yellow: #ffd84a; + --dog-blue: #23b7c9; + --dog-deep-blue: #087f98; + --dog-green: #78c64b; + --dog-coral: #f04f3d; + --dog-pink: #f58bb7; + --dog-purple: #a86be8; + --dog-dopamine-header: linear-gradient(105deg, #ffd84a 0 24%, #ff8a3d 24% 49%, #ff5b49 49% 74%, #a86be8 74% 100%); + --dog-line: 2px solid var(--dog-ink); + --dog-hard-shadow: 4px 4px 0 var(--dog-ink); + --dog-stroke-texture: + repeating-linear-gradient(7deg, rgba(255,255,255,.07) 0 2px, transparent 2px 8px), + repeating-linear-gradient(-5deg, rgba(32,32,29,.025) 0 1px, transparent 1px 6px); + color-scheme: light !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] body::before, -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-particles, -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-status, -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-quote, -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-hero-art-name { - display: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body { + background: + radial-gradient(circle at 13% 17%, rgba(240, 79, 61, .16) 0 2px, transparent 3px), + radial-gradient(circle at 82% 12%, rgba(35, 183, 201, .18) 0 2px, transparent 3px), + radial-gradient(circle at 65% 74%, rgba(120, 198, 75, .15) 0 1.5px, transparent 2.5px), + repeating-linear-gradient(7deg, rgba(32, 32, 29, .018) 0 1px, transparent 1px 7px), + var(--dog-paper) !important; + color: var(--dog-ink) !important; + font-family: ui-rounded, "SF Pro Rounded", "PingFang SC", system-ui, sans-serif !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] aside.app-shell-left-panel { - border: 0 !important; - border-right: 1px solid rgba(45, 67, 91, .1) !important; - border-radius: 0 !important; - background: rgba(255, 253, 249, .96) !important; - box-shadow: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body::before { + opacity: .18; + background-image: + radial-gradient(circle, var(--dog-coral) 0 1px, transparent 1.8px), + radial-gradient(circle, var(--dog-blue) 0 1px, transparent 1.8px), + radial-gradient(circle, var(--dog-green) 0 1px, transparent 1.8px) !important; + background-position: 17px 23px, 61px 79px, 103px 41px !important; + background-size: 149px 149px, 173px 173px, 191px 191px !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(main.main-surface, main.dream-skin-main-surface), -html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) { +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel { border: 0 !important; + border-right: 3px solid var(--dog-ink) !important; border-radius: 0 !important; - background: #fbfaf7 !important; + background: + repeating-linear-gradient(5deg, rgba(255, 255, 255, .035) 0 2px, transparent 2px 9px), + var(--dog-blue) !important; + color: var(--dog-ink) !important; + box-shadow: 5px 0 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel :where(button, a) { + border: 2px solid transparent !important; + border-radius: 11px 8px 12px 9px !important; + color: var(--dog-ink) !important; + font-weight: 760 !important; box-shadow: none !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(main.main-surface, main.dream-skin-main-surface) > header.app-header-tint { - border-bottom-color: rgba(45, 67, 91, .08) !important; - background: rgba(251, 250, 247, .98) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel :where(button, a):hover { + border-color: var(--dog-ink) !important; + background: color-mix(in srgb, var(--dog-yellow) 72%, white) !important; + box-shadow: 3px 3px 0 var(--dog-ink) !important; + transform: translate(-1px, -1px) rotate(-.15deg) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child { - min-height: 420px !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [aria-current="page"], +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [class~="bg-token-list-hover-background"] { + border: var(--dog-line) !important; + border-radius: 12px 7px 11px 9px !important; + background: linear-gradient(100deg, var(--dog-yellow), #ffe989) !important; + color: var(--dog-ink) !important; + box-shadow: 4px 4px 0 var(--dog-ink) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child > div:first-child { - border: 0 !important; - border-radius: 0 !important; - background-color: #fbfaf7 !important; - box-shadow: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel :where(svg, span, div) { + color: var(--dog-ink) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child > div:first-child::before { - width: 60%; - border-radius: 0; - background: linear-gradient(90deg, rgba(251, 250, 247, .98), rgba(251, 250, 247, .82) 72%, transparent) !important; +/* Native sidebar glyphs become small, uneven stickers while their original + SVG shapes keep the meaning and accessibility behavior supplied by Codex. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-icon] svg { + box-sizing: content-box !important; + width: 16px !important; + height: 16px !important; + padding: 3px !important; + overflow: visible !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 52% 43% 48% 45% !important; + color: var(--dog-ink) !important; + stroke-width: 2.35 !important; + filter: drop-shadow(2px 2px 0 var(--dog-ink)) !important; + transform: rotate(-2deg) !important; + transition: transform .16s ease, filter .16s ease, background .16s ease !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { - display: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-icon]:hover svg { + filter: drop-shadow(1px 1px 0 var(--dog-ink)) !important; + transform: translate(1px, 1px) rotate(2deg) scale(1.04) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home [data-feature="game-source"] { - color: #303235 !important; - font-size: clamp(38px, 4.2vw, 64px) !important; - letter-spacing: -.035em; - text-shadow: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-icon="new-chat"] svg { + background: var(--dog-yellow) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home [data-feature="game-source"]::before { - border: 0; - border-radius: 0; - padding: 0; - background: transparent; - color: #2477ef; - box-shadow: none; - font-size: 12px; - letter-spacing: .14em; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-icon="pull-requests"] svg { + background: var(--dog-green) !important; + transform: rotate(2deg) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home .group\/home-suggestions [class~="grid"] > :nth-child(n + 3) { - display: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-icon="sites"] svg { + background: color-mix(in srgb, var(--dog-cream) 72%, var(--dog-blue)) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home .group\/home-suggestions [class~="grid"] { - grid-template-columns: repeat(2, minmax(0, 240px)) !important; - justify-content: start !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-icon="scheduled"] svg { + background: var(--dog-pink) !important; + transform: rotate(2.5deg) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home .group\/home-suggestions button { - min-height: 96px !important; - border-color: rgba(59, 93, 133, .12) !important; - border-radius: 18px !important; - background: #fff !important; - color: #303235 !important; - box-shadow: 0 7px 20px rgba(47, 69, 91, .06) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-icon="plugins"] svg { + background: var(--dog-purple) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(.composer-surface-chrome, .dream-skin-composer) { - width: min(72%, 820px) !important; - margin-inline: 0 auto !important; - border-color: rgba(51, 91, 137, .15) !important; - border-radius: 18px !important; - background: #fff !important; - color: #4b5056 !important; - box-shadow: 0 10px 28px rgba(48, 69, 92, .07) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-icon="security"] svg { + background: var(--dog-coral) !important; + transform: rotate(1.5deg) !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) :where(article, .message, [class*="surface"]:not(:is(.composer-surface-chrome, .dream-skin-composer))) { - border-color: rgba(50, 85, 125, .1) !important; - background: #fff !important; - color: #303235 !important; - box-shadow: 0 8px 24px rgba(45, 66, 87, .055) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-project] svg { + box-sizing: content-box !important; + width: 16px !important; + height: 16px !important; + padding: 2px !important; + overflow: visible !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 5px 3px 5px 4px !important; + background: var(--dog-yellow) !important; + color: var(--dog-ink) !important; + stroke-width: 2.25 !important; + filter: drop-shadow(1px 1px 0 var(--dog-ink)) !important; + transform: rotate(-1deg) !important; +} + +/* Give every sidebar label the same breathing room, including native project + folders whose markup differs from Codex's primary navigation rows. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel :is( + [data-dream-dog-icon], + [data-dream-dog-project] +) { + column-gap: 8px !important; } -@media (max-width: 760px) { - html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child { - flex-direction: column !important; - } +/* Utility actions use the same hand-painted visual language as navigation, + but stay slightly smaller so the top and bottom chrome remains quiet. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action] svg { + box-sizing: content-box !important; + width: 14px !important; + height: 14px !important; + padding: 3px !important; + overflow: visible !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 52% 44% 49% 43% !important; + color: var(--dog-ink) !important; + stroke-width: 2.3 !important; + filter: drop-shadow(2px 2px 0 var(--dog-ink)) !important; + transform: rotate(-2deg) !important; + transition: transform .16s ease, filter .16s ease !important; +} - html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child, - html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:nth-child(2) { - width: 100% !important; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action] { + column-gap: 8px !important; +} - html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(.composer-surface-chrome, .dream-skin-composer) { - width: 100% !important; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action]:hover svg { + filter: drop-shadow(1px 1px 0 var(--dog-ink)) !important; + transform: translate(1px, 1px) rotate(2deg) !important; } -/* Dark concept themes must also override Codex's light-shell text tokens. - These tokens are attached to conversation internals rather than inherited - from :is(main.main-surface, main.dream-skin-main-surface), so setting only the shell color is insufficient. */ -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"], - [data-dream-theme="shanhai-nexus"] -) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) .thread-scroll-container { - --color-token-conversation-body: color-mix(in srgb, var(--ds-text) 94%, transparent); - --color-token-text-secondary: color-mix(in srgb, var(--ds-text) 76%, transparent); - --color-token-text-tertiary: color-mix(in srgb, var(--ds-text) 58%, transparent); - --color-token-conversation-summary-leading: color-mix(in srgb, var(--ds-text) 82%, transparent); - --color-token-conversation-summary-trailing: color-mix(in srgb, var(--ds-text) 64%, transparent); - --color-token-conversation-header: color-mix(in srgb, var(--ds-text) 68%, transparent); - --color-token-description-foreground: color-mix(in srgb, var(--ds-text) 70%, transparent); - --shimmer-text-secondary: color-mix(in srgb, var(--ds-text) 70%, transparent); - --shimmer-contrast: var(--ds-text); - color: var(--ds-text) !important; - text-shadow: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action="search"] svg { + background: var(--dog-yellow) !important; } -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"], - [data-dream-theme="shanhai-nexus"] -) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) > header.app-header-tint :where(span, button, svg) { - color: var(--ds-text) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action="activity"] svg { + background: var(--dog-coral) !important; + transform: rotate(2deg) !important; } -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"], - [data-dream-theme="shanhai-nexus"] -) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container [class*="_markdownContent_"] { - padding: 13px 15px; - border: 1px solid color-mix(in srgb, var(--ds-green) 34%, transparent); - border-radius: max(var(--ds-radius), 2px); - background: color-mix(in srgb, var(--ds-panel) 90%, transparent); - box-shadow: 0 12px 30px rgba(0, 0, 0, .22); - color: var(--ds-text) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action="quick-chat"] svg { + background: var(--dog-green) !important; } -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"], - [data-dream-theme="shanhai-nexus"] -) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container [class*="_markdownContent_"] - :where(p, li, h1, h2, h3, h4, h5, h6, strong, em, blockquote, span) { - color: var(--ds-text) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action="profile"] { + column-gap: 8px !important; } -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"], - [data-dream-theme="shanhai-nexus"] -) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container [class*="_markdownContent_"] a { - color: var(--ds-lime) !important; - text-decoration-color: color-mix(in srgb, var(--ds-lime) 58%, transparent) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action="profile"] :where([class*="avatar" i], [class*="Avatar"], img) { + outline: 2px solid var(--dog-ink) !important; + outline-offset: 1px !important; + border-radius: 48% 43% 52% 45% !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + transform: rotate(-2deg) !important; } -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"] -) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container :where( - .text-token-conversation-body, - .text-token-conversation-summary-leading, - .text-token-conversation-summary-trailing, - .text-token-description-foreground, - .text-token-text-secondary, - .text-token-text-tertiary, - .group\/activity-header, - .group\/activity-header span, - .group\/activity-header svg - ) { - color: color-mix(in srgb, var(--ds-text) 78%, transparent) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action="voice"] { + column-gap: 8px !important; } -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"], - [data-dream-theme="shanhai-nexus"] -) :is(.composer-surface-chrome, .dream-skin-composer) :where(*, .ProseMirror) { - color: var(--ds-text) !important; - caret-color: var(--ds-lime) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action="voice"] svg { + background: var(--dog-purple) !important; } -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"], - [data-dream-theme="shanhai-nexus"] -) :is(.composer-surface-chrome, .dream-skin-composer) :where([data-placeholder], [data-placeholder] *) { - color: color-mix(in srgb, var(--ds-text) 58%, transparent) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [data-dream-dog-action="help"] svg { + background: var(--dog-yellow) !important; + transform: rotate(2deg) !important; } -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"], - [data-dream-theme="shanhai-nexus"] -) .dream-skin-home [class*="_homeUtilityBar_"] { - border-color: color-mix(in srgb, var(--ds-green) 28%, transparent) !important; - background: color-mix(in srgb, var(--ds-panel) 96%, transparent) !important; - color: var(--ds-text) !important; +/* Titlebar navigation sits outside the aside, so it gets a dedicated compact + sticker treatment without changing the native hit targets. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-chrome-action] svg { + box-sizing: content-box !important; + width: 14px !important; + height: 14px !important; + padding: 3px !important; + overflow: visible !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 50% !important; + background: var(--dog-cream) !important; + color: var(--dog-ink) !important; + stroke-width: 2.3 !important; + filter: drop-shadow(2px 2px 0 var(--dog-ink)) !important; + transition: transform .15s ease, filter .15s ease !important; } -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"], - [data-dream-theme="shanhai-nexus"] -) .dream-skin-home [class*="_homeUtilityBar_"] :where(button, span, svg) { - color: var(--ds-text) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] button[data-dream-dog-chrome-action]:hover svg { + transform: scale(1.12) !important; + filter: drop-shadow(3px 3px 0 var(--dog-ink)) !important; } -/* Codex places a translucent light token layer inside the sidebar. On dark - concept themes it washed the navy/black shell into gray, so let the themed - sidebar itself provide the surface. */ -html.codex-dream-skin:is( - [data-dream-theme="neon-star-hunter"], - [data-dream-theme="hacker-zero"] -) aside.app-shell-left-panel [class*="bg-token-bg-secondary"] { - background: transparent !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-chrome-action="sidebar"] svg { + background: var(--dog-yellow) !important; } -/* ------------------------------------------------------------------------- - Real split-studio composition +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-chrome-action="back"] svg { + background: color-mix(in srgb, var(--dog-cream) 72%, var(--dog-blue)) !important; +} - The upstream Codex home page is a vertical stack (welcome area, then - banners/composer). Merely narrowing the welcome card did not create a split - layout. This grid reserves a dedicated artwork studio on the left and moves - the real Codex welcome/composer stack to the right. No fake controls are - introduced; the actual composer remains interactive. - ------------------------------------------------------------------------- */ -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child { - position: relative !important; - display: grid !important; - grid-template-columns: minmax(250px, 44%) minmax(0, 56%) !important; - grid-template-rows: minmax(0, 1fr) auto !important; - gap: 14px 18px !important; - min-height: 100% !important; - padding: 20px 22px !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-chrome-action="forward"] svg { + background: var(--dog-green) !important; + transform: rotate(2deg) !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child::before { - content: ""; - grid-column: 1; - grid-row: 1 / 3; - min-width: 0; - min-height: 0; - border: 1px solid rgba(255, 139, 38, .32); - border-radius: 26px; - background-color: #eaf7ff; - background-image: - linear-gradient(0deg, rgba(29, 59, 72, .4), transparent 42%), - var(--dream-skin-art); - background-repeat: no-repeat; - background-position: center, 8% 54%; - background-size: 100% 100%, cover; - box-shadow: 0 18px 38px rgba(57, 116, 148, .15), inset 0 0 0 1px rgba(255, 255, 255, .62); - pointer-events: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-chrome-action]:hover svg { + filter: drop-shadow(1px 1px 0 var(--dog-ink)) !important; + transform: translate(1px, 1px) rotate(2deg) scale(1.04) !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child { +/* Output and sources — a compact folder-note popover. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-panel] { + overflow: hidden !important; + border: 3px solid var(--dog-ink) !important; + border-radius: 12px 8px 15px 10px !important; + background: + repeating-linear-gradient(0deg, transparent 0 20px, rgba(32, 32, 29, .035) 21px 22px), + var(--dog-cream) !important; + color: var(--dog-ink) !important; + box-shadow: 7px 7px 0 var(--dog-ink) !important; + transform: rotate(-.15deg) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-header] { position: relative !important; - z-index: 1; - grid-column: 2; - grid-row: 1; - min-width: 0 !important; - min-height: 0 !important; - height: auto !important; - padding: 0 !important; - align-items: stretch !important; + top: 0 !important; + height: 30px !important; + border-bottom: 2px solid var(--dog-ink) !important; + color: var(--dog-ink) !important; + font-weight: 850 !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child { - width: 100% !important; - min-height: 0 !important; - height: auto !important; - padding: 18px !important; - border: 1px solid rgba(70, 171, 194, .2) !important; - border-radius: 24px !important; - background: rgba(255, 255, 255, .86) !important; - box-shadow: 0 14px 30px rgba(58, 117, 148, .1) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-header="output"] { + background: var(--dog-yellow) !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child::before, -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { - display: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-header="sources"] { + background: var(--dog-coral) !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child > div:first-child { - min-height: 0 !important; - align-items: flex-start !important; - justify-content: flex-start !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-add] { + display: inline-flex !important; + width: 21px !important; + height: 21px !important; + min-width: 21px !important; padding: 0 !important; - opacity: 0 !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 50% 44% 52% 46% !important; + background: var(--dog-green) !important; + color: var(--dog-ink) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + transition: transform 140ms ease, box-shadow 140ms ease !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { - content: "猫猫工位已就绪\A\A扳手就位,灵感启动。\A选择一个项目,然后开始创造。"; - position: absolute; - inset: 28px 28px auto; - display: block !important; - color: #293541; - font: 700 clamp(18px, 2vw, 30px)/1.42 ui-rounded, "PingFang SC", sans-serif; - white-space: pre-line; - text-shadow: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-add]:hover { + box-shadow: 1px 1px 0 var(--dog-ink) !important; + transform: translate(1px, 1px) rotate(9deg) !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:nth-child(2) { - position: relative !important; - z-index: 1; - grid-column: 2; - grid-row: 2; - width: auto !important; - min-width: 0 !important; - min-height: 0 !important; - padding: 0 !important; - border: 0 !important; - background: transparent !important; - box-shadow: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-row] { + column-gap: 8px !important; + min-height: 29px !important; + padding: 3px 5px !important; + border: 2px dashed transparent !important; + border-radius: 8px 5px 9px 6px !important; + color: var(--dog-ink) !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home [data-feature="game-source"] { - color: #293541 !important; - font-size: clamp(24px, 2.6vw, 36px) !important; - text-shadow: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-row] [data-slot="thread-summary-panel-item-leading"] { + box-sizing: border-box !important; + width: 22px !important; + height: 22px !important; + margin-inline-end: 0 !important; + padding: 3px !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 5px 3px 6px 4px !important; + background: var(--dog-blue) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + transform: rotate(-2deg) !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home [data-feature="game-source"]::before { - border-color: rgba(73, 166, 197, .24) !important; - background: linear-gradient(100deg, rgba(74, 203, 173, .95), rgba(255, 138, 36, .92)) !important; - color: #fff !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-row="image"] [data-slot="thread-summary-panel-item-leading"] { + background: var(--dog-green) !important; + transform: rotate(2deg) !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-hero-art-name { - right: auto; - top: auto; - bottom: 80px; - left: 5%; - color: rgba(255, 255, 255, .92); - text-shadow: 0 2px 12px rgba(27, 52, 63, .44); +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-row="create"] { + background: color-mix(in srgb, var(--dog-yellow) 35%, transparent) !important; } -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-composer-stamp, -html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-washi { - display: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-row]:hover { + border-color: var(--dog-ink) !important; + background: #fff0a8 !important; + transform: rotate(.2deg) !important; } -@media (max-width: 760px) { - html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child { - display: flex !important; - flex-direction: column !important; - padding: 14px !important; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-dream-dog-resource-view-all] { + width: fit-content !important; + margin-top: 3px !important; + padding-inline: 7px !important; + border-style: solid !important; + background: var(--dog-green) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + font-weight: 800 !important; + transform: rotate(-1deg) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel :is( + [data-dream-dog-icon], + [data-dream-dog-project] +)[aria-current="page"] svg, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel :is( + [data-dream-dog-icon], + [data-dream-dog-project] +)[class~="bg-token-list-hover-background"] svg, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel [aria-current="page"] :is( + [data-dream-dog-icon], + [data-dream-dog-project] +) svg { + background: var(--dog-yellow) !important; + filter: drop-shadow(2px 2px 0 var(--dog-coral)) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel :is( + [class*=_Project], + [class*=_Thread], + [class*=_Conversation] +) { + border-radius: 10px 7px 11px 8px !important; +} - html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child::before { - width: 100%; - min-height: 240px; - flex: 0 0 240px; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel :is( + [class*=_SectionHeader], + [class*=_GroupHeader] +) { + margin-block: 8px 4px !important; + color: color-mix(in srgb, var(--dog-ink) 72%, var(--dog-deep-blue)) !important; + font-size: 12px !important; + font-weight: 900 !important; + letter-spacing: .035em !important; + text-transform: uppercase !important; } -/* ------------------------------------------------------------------------- - Real terminal-grid composition: a dense system console occupies the left, - the agent artwork becomes a separate right module, and the real Codex - composer remains a full-width command line below. - ------------------------------------------------------------------------- */ -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child { +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-radix-scroll-area-viewport] { + scrollbar-color: var(--dog-coral) transparent !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-main-surface, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.main-surface { + border: 0 !important; + border-radius: 0 !important; + background: + repeating-linear-gradient(-3deg, rgba(32, 32, 29, .012) 0 1px, transparent 1px 8px), + var(--dog-paper) !important; + color: var(--dog-ink) !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="_MainContentViewport_"] { position: relative !important; - display: grid !important; - grid-template-columns: minmax(0, 1.55fr) minmax(210px, .72fr) !important; - grid-template-rows: minmax(0, 1fr) auto !important; - gap: 8px !important; - min-height: 100% !important; - padding: 18px !important; + background: + linear-gradient(to bottom, + transparent 0 59px, + transparent 59px), + radial-gradient(circle at 13% 17%, rgba(240, 79, 61, .16) 0 2px, transparent 3px), + radial-gradient(circle at 82% 12%, rgba(35, 183, 201, .18) 0 2px, transparent 3px), + radial-gradient(circle at 65% 74%, rgba(120, 198, 75, .15) 0 1.5px, transparent 2.5px), + repeating-linear-gradient(7deg, rgba(32, 32, 29, .018) 0 1px, transparent 1px 7px), + var(--dog-dopamine-header) top / 100% 59px no-repeat, + var(--dog-paper) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="_MainContentViewport_"]::before { + content: "" !important; + position: absolute !important; + z-index: 0 !important; + inset: 0 0 auto !important; + height: 59px !important; + pointer-events: none !important; + border: 0 !important; + border-bottom: 0 !important; + background: + var(--dog-stroke-texture), + var(--dog-dopamine-header) !important; + box-shadow: none !important; } -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child::before { - content: "ROOT@HX-0:~$ systemctl status codex-agent\A\A[ OK ] theme engine online\A[ OK ] local workspace mounted\A[ NET ] encrypted tunnel ready\A[ CPU ] 12% [ MEM ] 28%\A\A> awaiting next instruction_"; - grid-column: 1; - grid-row: 1; - min-width: 0; - min-height: 0; - padding: 34px 16px 16px; - overflow: hidden; - border: 1px solid rgba(32, 249, 118, .46); +/* The thread view keeps an 8px native titlebar spacer above the themed + layers. Paint that exact seam at the viewport edge so it also stays covered + after switching between conversations. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="_MainContentViewport_"]::after { + content: "" !important; + position: absolute !important; + z-index: 40 !important; + inset: 0 auto auto 0 !important; + width: 9px !important; + height: 59px !important; + pointer-events: none !important; background: - linear-gradient(rgba(30, 255, 112, .04) 1px, transparent 1px), - linear-gradient(90deg, rgba(30, 255, 112, .04) 1px, transparent 1px), - #010604; - background-size: 24px 24px; - color: #75ffae; - font: 11px/1.72 "SF Mono", Consolas, monospace; - white-space: pre-wrap; - box-shadow: inset 0 20px rgba(24, 255, 113, .035); - pointer-events: none; + linear-gradient(to bottom, transparent 0 56px, var(--dog-ink) 56px 59px), + var(--dog-stroke-texture), + var(--dog-dopamine-header) !important; } -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child::after { - content: "[ SYSTEM LOG ] 23:47:09\A--------------------------------\A 23:47:02 handshake complete\A 23:47:04 palette verified\A 23:47:08 layout modules ready"; - grid-column: 1; - grid-row: 1; - align-self: end; - min-height: 128px; - margin: 0 8px 8px; - padding: 12px; - border: 1px solid rgba(32, 249, 118, .26); - background: rgba(1, 8, 5, .96); - color: #4fcf83; - font: 9px/1.6 "SF Mono", Consolas, monospace; - white-space: pre-wrap; - pointer-events: none; +/* Keep the native titlebar's pale separator from showing through below the + hand-drawn header. This narrow overlay belongs to the theme chrome, so it + remains stable while the conversation viewport scrolls. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome { + z-index: 32 !important; } -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:first-child { - position: relative !important; - z-index: 1; - grid-column: 2; - grid-row: 1; - min-width: 0 !important; - min-height: 0 !important; - height: auto !important; - padding: 0 !important; - align-items: stretch !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome::before { + content: "" !important; + position: absolute !important; + z-index: 1 !important; + inset: 46px 0 auto !important; + height: 13px !important; + pointer-events: none !important; + background: + linear-gradient(to bottom, transparent 0 10px, var(--dog-ink) 10px 13px), + var(--dog-stroke-texture), + var(--dog-dopamine-header) !important; } -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:first-child > div:first-child { - width: 100% !important; - min-height: 0 !important; - height: auto !important; - padding: 0 !important; - border: 1px solid rgba(32, 249, 118, .46) !important; - background-position: 95% center !important; - background-size: auto 100% !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome::after { + content: "" !important; + position: absolute !important; + z-index: 0 !important; + inset: 0 0 auto auto !important; + width: 70px !important; + height: 46px !important; + pointer-events: none !important; + background: + var(--dog-stroke-texture), + var(--dog-dopamine-header) !important; } -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:first-child > div:first-child::before { - width: 100% !important; - background: linear-gradient(0deg, rgba(0, 5, 2, .58), transparent 56%) !important; +/* Task conversations and the new-conversation home use different viewport + geometry. In both cases the fixed titlebar already draws the upper rule; + keep the 13px seam painted, but do not draw a second lower rule. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome:not(.dream-skin-home-shell)::before { + background: var(--dog-dopamine-header) !important; + border-bottom: 0 !important; + box-shadow: none !important; } -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:first-child > div:first-child > div:first-child { - opacity: 0 !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main:not(.dream-skin-home-shell) [class*="_MainContentViewport_"]::after { + background: var(--dog-dopamine-header) !important; + border-bottom: 0 !important; + box-shadow: none !important; } -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:nth-child(2) { - position: relative !important; - z-index: 1; - grid-column: 1 / 3; - grid-row: 2; - width: auto !important; - min-width: 0 !important; - min-height: 0 !important; - padding: 0 !important; - border: 0 !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell::before { background: transparent !important; + border-bottom: 0 !important; box-shadow: none !important; } -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-hero-art-name { - top: 92px; - right: 5%; - font: 11px/1.2 "SF Mono", Consolas, monospace; - letter-spacing: .16em; - transform: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class*="_MainContentViewport_"]::after { + background: transparent !important; + border-bottom: 0 !important; + box-shadow: none !important; } -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-composer-stamp, -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-washi, -html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-quote { - display: none !important; +/* Plan A: the thread header is an opaque cream bar with its own 6px ribbon, + so the conversation viewport drops the legacy 59px rainbow backing and the + seam covers that used to sit behind the old transparent header. These rules + must come after the legacy ones above — equal-specificity ties break by + source order. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main:not(.dream-skin-home-shell) [class*="_MainContentViewport_"] { + background: + radial-gradient(circle at 13% 17%, rgba(240, 79, 61, .16) 0 2px, transparent 3px), + radial-gradient(circle at 82% 12%, rgba(35, 183, 201, .18) 0 2px, transparent 3px), + radial-gradient(circle at 65% 74%, rgba(120, 198, 75, .15) 0 1.5px, transparent 2.5px), + repeating-linear-gradient(7deg, rgba(32, 32, 29, .018) 0 1px, transparent 1px 7px), + var(--dog-paper) !important; } -/* ------------------------------------------------------------------------- - Real paper-board composition: character illustration, pinned work sheet and - the real composer form a three-column desk instead of another banner. - ------------------------------------------------------------------------- */ -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child { - position: relative !important; - display: grid !important; - grid-template-columns: minmax(220px, 36%) minmax(0, 64%) !important; - grid-template-rows: minmax(0, 1fr) auto !important; - gap: 16px !important; - min-height: 100% !important; - padding: 22px 24px !important; - background: - repeating-linear-gradient(0deg, transparent 0 25px, rgba(109, 75, 40, .045) 25px 26px), - rgba(246, 226, 184, .72); +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main:not(.dream-skin-home-shell) [class*="_MainContentViewport_"]::before, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main:not(.dream-skin-home-shell) [class*="_MainContentViewport_"]::after, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome:not(.dream-skin-home-shell)::before, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome:not(.dream-skin-home-shell)::after { + background: none !important; } -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child::before { - content: ""; - grid-column: 1; - grid-row: 1 / 3; - min-width: 0; - min-height: 0; - border: 2px solid rgba(116, 73, 34, .34); - border-radius: 42% 8px 18px 8px; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class~="draggable"][class*="grid-cols-"] { + border-bottom: 0 !important; background: - linear-gradient(0deg, rgba(80, 50, 25, .35), transparent 42%), - var(--dream-skin-art) 9% 56% / cover no-repeat; - box-shadow: 6px 8px 0 rgba(101, 61, 25, .14); - pointer-events: none; + var(--dog-stroke-texture), + var(--dog-dopamine-header) !important; + color: var(--dog-ink) !important; + box-shadow: + -12px 0 0 var(--dog-yellow), + 160px 0 0 var(--dog-yellow) !important; } -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child::after { - content: "今日委托 · 配方记录"; - position: absolute; - top: 34px; - left: calc(36% + 58px); - z-index: 2; - padding: 7px 18px; - border: 1px dashed rgba(105, 66, 30, .36); - background: #f7dfae; - color: #704326; - font: 700 11px/1 ui-rounded, "PingFang SC", sans-serif; - letter-spacing: .08em; - box-shadow: 3px 4px 0 rgba(101, 61, 25, .1); - transform: rotate(-1deg); - pointer-events: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class~="draggable"][class*="grid-cols-"] :where(button, [role="button"]) { + color: var(--dog-ink) !important; + font-weight: 850 !important; } -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child { - position: relative !important; - z-index: 1; - grid-column: 2; - grid-row: 1; - min-width: 0 !important; - min-height: 0 !important; - height: auto !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="_MainContentViewport_"] [class*="contain:layout_paint"] { + margin-left: 0 !important; + width: calc(100% + 8px) !important; + padding-left: 16px !important; + overflow: visible !important; + border-bottom: 0 !important; + background: + var(--dog-stroke-texture), + var(--dog-yellow) !important; + box-shadow: + -12px 0 0 var(--dog-yellow), + 120px 0 0 var(--dog-yellow) !important; + transform: translateX(-8px) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class~="draggable"][class*="grid-cols-"] > :first-child button.aspect-square { + width: 30px !important; + height: 29px !important; + margin-right: 5px !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 8px 10px 7px 9px !important; + background: var(--dog-deep-blue) !important; + color: #fff9e8 !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + transform: rotate(-1.5deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class~="draggable"][class*="grid-cols-"] > :first-child button[class*="max-w-"] { + min-height: 28px !important; + padding: 1px 7px 3px !important; + overflow: visible !important; + border: 0 !important; + border-radius: 0 !important; + background: transparent !important; + color: var(--dog-ink) !important; + font-weight: 900 !important; + letter-spacing: .025em !important; + box-shadow: inset 0 -4px 0 rgba(240, 79, 61, .72) !important; + text-shadow: 1px 1px 0 rgba(255, 249, 232, .72) !important; + transform: rotate(-.25deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class~="draggable"][class*="grid-cols-"] > :first-child button:not(.aspect-square):not([class*="max-w-"]) { + width: 29px !important; + min-width: 29px !important; + height: 28px !important; + min-height: 28px !important; padding: 0 !important; - align-items: stretch !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 48% 52% 45% 55% !important; + background: var(--dog-coral) !important; + color: #fff9e8 !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + transform: rotate(2deg); } -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child { - width: 100% !important; - min-height: 0 !important; - height: auto !important; - padding: 50px 24px 20px !important; - border: 1px solid rgba(117, 74, 33, .3) !important; - border-radius: 4px 18px 4px 18px !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] button.aspect-square:is( + [aria-label="Share"], + [aria-label="切换置顶摘要"] +) { + width: 29px !important; + height: 28px !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 9px 7px 10px 8px !important; + background: var(--dog-green) !important; + color: var(--dog-ink) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + transform: rotate(.8deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] button.aspect-square[aria-label="Share"] { + background: var(--dog-coral) !important; + color: #fff9e8 !important; + transform: rotate(-1deg); +} + +/* Current unified shell: its thread toolbar is a transparent fixed header + rather than the older app-header-tint node. Paint the fixed layer itself so + scrolled messages cannot show through the titlebar. + Plan A: quiet cream paper body; the rainbow is demoted to a 6px ribbon + hugging the bottom edge above the ink border. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-main-surface:not(.dream-skin-home-shell) > header[class~="fixed"][class~="z-30"] { background: - repeating-linear-gradient(0deg, transparent 0 25px, rgba(114, 80, 46, .065) 25px 26px), - #fff0ca !important; - box-shadow: 5px 7px 0 rgba(101, 61, 25, .12) !important; + linear-gradient(100deg, + #ffd84a 0 24%, + #ff5b49 24% 45%, + #23b7c9 45% 66%, + #78c64b 66% 84%, + #a86be8 84% 100%) left 0 bottom 3px / 100% 6px no-repeat, + var(--dog-stroke-texture), + var(--dog-cream) !important; + border-bottom: 3px solid var(--dog-ink) !important; + box-shadow: 0 4px 0 rgba(32, 32, 29, .11) !important; + backdrop-filter: none !important; } -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child::before, -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { - display: none !important; +/* Plan A: thread title chip becomes a yellow sticker card. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-main-surface:not(.dream-skin-home-shell) > header[class~="fixed"] button.cursor-interaction { + background: var(--dog-yellow) !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 10px 8px 11px 9px !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + color: var(--dog-ink) !important; + padding: 3px 10px !important; + transform: rotate(-.6deg); } -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child > div:first-child { - min-height: 0 !important; - align-items: flex-start !important; - justify-content: flex-start !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-main-surface:not(.dream-skin-home-shell) > header[class~="fixed"] button.cursor-interaction:hover { + background: var(--dog-yellow) !important; + box-shadow: 3px 3px 0 var(--dog-ink) !important; + transform: rotate(-.6deg) translate(-1px, -1px) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-main-surface > header.app-header-tint, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.main-surface > header.app-header-tint, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] header.app-header-tint, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is([class*="_AppHeader_"], [class*="_TitleBar_"], [class*="_Titlebar_"], [class*="_TopBar_"]) { + border: 0 !important; + border-bottom: 3px solid var(--dog-ink) !important; + background: + repeating-linear-gradient(3deg, rgba(255, 255, 255, .08) 0 2px, transparent 2px 10px), + var(--dog-dopamine-header) !important; + color: var(--dog-ink) !important; + box-shadow: 0 4px 0 rgba(32, 32, 29, .11) !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell > header[class~="fixed"][class~="z-30"] { + background: + var(--dog-stroke-texture), + linear-gradient(100deg, + #ffd84a 0 24%, + #ff5b49 24% 45%, + #23b7c9 45% 66%, + #78c64b 66% 84%, + #a86be8 84% 100%) !important; + border-bottom: 3px solid var(--dog-ink) !important; + box-shadow: 0 4px 0 rgba(32, 32, 29, .11) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] header.app-header-tint :where(button, [role="button"]), +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell > header[class~="fixed"] :where(button, [role="button"]), +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is([class*="_AppHeader_"], [class*="_TitleBar_"], [class*="_Titlebar_"], [class*="_TopBar_"]) :where(button, [role="button"]) { + border: 2.5px solid var(--dog-ink) !important; + border-radius: 50% !important; + background: var(--dog-cream) !important; + color: var(--dog-ink) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] header.app-header-tint :where(button, [role="button"]):hover, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell > header[class~="fixed"] :where(button, [role="button"]):hover, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is([class*="_AppHeader_"], [class*="_TitleBar_"], [class*="_Titlebar_"], [class*="_TopBar_"]) :where(button, [role="button"]):hover { + border-color: var(--dog-ink) !important; + background: var(--dog-yellow) !important; + box-shadow: 3px 3px 0 var(--dog-ink) !important; + transform: translate(-1px, -1px) !important; +} + +/* The icon circle is the whole button face: keep the hit target transparent. + Must come after the generic header-button rules above — equal specificity + !important ties are broken by source order. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body button[data-dream-dog-chrome-action][aria-label], +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body button[data-dream-dog-chrome-action][aria-label]:hover { + background: transparent !important; + border: none !important; + box-shadow: none !important; + transform: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-message-author-role] { + border: var(--dog-line) !important; + border-radius: 15px 10px 16px 11px !important; + background: var(--dog-cream) !important; + color: var(--dog-ink) !important; + box-shadow: 4px 4px 0 rgba(32, 32, 29, .92) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-message-author-role="user"] { + background: var(--dog-yellow) !important; + transform: rotate(.08deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [class*=_Thread], + [class*=_Conversation], + [class*=_MessageList], + [class*=_Timeline] +) { + color: var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [class*=_Thread], + [class*=_Conversation], + [class*=_MessageList], + [class*=_Timeline] +) :where(h1, h2, h3, strong) { + color: var(--dog-ink) !important; + font-weight: 900 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [class*=_Thread], + [class*=_Conversation], + [class*=_MessageList], + [class*=_Timeline] +) :where(a) { + color: var(--dog-deep-blue) !important; + text-decoration-thickness: 2px !important; + text-underline-offset: 3px !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] article { + border: var(--dog-line) !important; + border-radius: 14px 9px 15px 10px !important; + background: rgba(255, 250, 240, .97) !important; + color: var(--dog-ink) !important; + box-shadow: 4px 4px 0 rgba(32, 32, 29, .9) !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [data-testid*="tool"], + [data-testid*="diff"], + [data-testid*="file"], + [class*="_ToolCall_"], + [class*="_Diff_"], + [class*="_FileChange_"] +) { + border: var(--dog-line) !important; + border-radius: 12px 8px 13px 9px !important; + background: color-mix(in srgb, var(--dog-green) 20%, var(--dog-cream)) !important; + color: var(--dog-ink) !important; + box-shadow: 3px 3px 0 var(--dog-ink) !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [data-testid*="tool"], + [data-testid*="diff"], + [data-testid*="file"], + [class*="_ToolCall_"], + [class*="_Diff_"], + [class*="_FileChange_"] +) > :first-child { + border-bottom: 2px solid rgba(32, 32, 29, .72) !important; + background: color-mix(in srgb, var(--dog-green) 42%, var(--dog-cream)) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="_ArtifactPanel_"], +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [class*="_RightPanel_"], + [class*="_Inspector_"], + [data-testid*="artifact"], + [data-testid*="inspector"] +) { + border: var(--dog-line) !important; + border-right: 0 !important; + border-radius: 15px 0 0 12px !important; + background: var(--dog-cream) !important; + color: var(--dog-ink) !important; + box-shadow: -4px 4px 0 var(--dog-ink) !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="_ArtifactPanel_"] :where(button, [role="button"]), +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is([class*="_RightPanel_"], [class*="_Inspector_"]) :where(button, [role="button"]) { + border-radius: 8px 6px 9px 7px !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [class*=_ArtifactPanel_], + [class*=_RightPanel_], + [class*=_Inspector_], + [class*=_Output], + [class*=_Sources] +) :is([class*=_Header], [class*=_SectionHeader]) { + border-bottom: var(--dog-line) !important; + background: var(--dog-yellow) !important; + color: var(--dog-ink) !important; + font-weight: 900 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [class*=_ArtifactPanel_], + [class*=_RightPanel_], + [class*=_Inspector_], + [class*=_Output], + [class*=_Sources] +) :is([class*=_Item], [class*=_Row], li) { + border-bottom: 2px dashed color-mix(in srgb, var(--dog-ink) 35%, transparent) !important; + background: transparent !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] div[class~="rounded-3xl"][class~="bg-surface-elevated-secondary"] { + border: 3px solid var(--dog-ink) !important; + border-radius: 18px 11px 20px 13px !important; + background: + var(--dog-stroke-texture), + var(--dog-cream) !important; + color: var(--dog-ink) !important; + box-shadow: + inset 0 38px 0 var(--dog-green), + 6px 6px 0 var(--dog-ink) !important; + backdrop-filter: none !important; + outline: 3px solid var(--dog-ink) !important; + outline-offset: -3px !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body div[class~="rounded-3xl"][class~="bg-surface-elevated-secondary"] { + background-color: var(--dog-cream) !important; + background-image: var(--dog-stroke-texture) !important; + border-color: var(--dog-ink) !important; + color: var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] div[class~="rounded-3xl"][class~="bg-surface-elevated-secondary"] div[class~="sticky"][class~="bg-surface-elevated-secondary"] { + border: 0 !important; + border-bottom: 3px solid var(--dog-ink) !important; + border-radius: 14px 8px 0 0 !important; + background: + var(--dog-stroke-texture), + var(--dog-green) !important; + color: var(--dog-ink) !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body div[class~="rounded-3xl"][class~="bg-surface-elevated-secondary"] div[class~="sticky"][class~="bg-surface-elevated-secondary"] { + background-color: var(--dog-green) !important; + background-image: var(--dog-stroke-texture) !important; + border-bottom-color: var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body div[class~="rounded-3xl"][class~="bg-surface-elevated-secondary"] div[class~="sticky"] { + border: 0 !important; + border-bottom: 3px solid var(--dog-ink) !important; + background-color: var(--dog-green) !important; + background-image: var(--dog-stroke-texture) !important; + color: var(--dog-ink) !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body div[class~="rounded-3xl"][class~="bg-surface-elevated-secondary"] div[class~="sticky"]::before { + background: var(--dog-green) !important; + border: 0 !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .thread-scroll-container [class*="summary-panel-item"] { + margin: 3px 0 !important; + padding: 7px 8px !important; + border: 2px solid transparent !important; + border-radius: 9px 6px 10px 7px !important; + color: var(--dog-ink) !important; + font-weight: 750 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .thread-scroll-container [class*="summary-panel-item"]:hover { + border-color: var(--dog-ink) !important; + background: var(--dog-yellow) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; +} + +/* Resource popover cascade guard. The generic elevated-panel rules above are + intentionally broad, so the semantic resource hooks must paint last. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-panel] { + border: 3px solid var(--dog-ink) !important; + border-radius: 12px 8px 15px 10px !important; + background: + repeating-linear-gradient(0deg, transparent 0 20px, rgba(32, 32, 29, .035) 21px 22px), + var(--dog-cream) !important; + box-shadow: 7px 7px 0 var(--dog-ink) !important; + outline: 0 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-panel][class~="rounded-3xl"] [data-dream-dog-resource-header][class~="sticky"] { + height: 30px !important; + border: 0 !important; + border-bottom: 2px solid var(--dog-ink) !important; + border-radius: 0 !important; + color: var(--dog-ink) !important; + box-shadow: none !important; + font-weight: 850 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-panel][class~="rounded-3xl"] [data-dream-dog-resource-header="output"][class~="sticky"], +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-panel][class~="rounded-3xl"] [data-dream-dog-resource-header="output"][class~="sticky"]::before { + background: var(--dog-yellow) !important; + background-color: var(--dog-yellow) !important; + background-image: var(--dog-stroke-texture) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-panel][class~="rounded-3xl"] [data-dream-dog-resource-header="sources"][class~="sticky"], +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-panel][class~="rounded-3xl"] [data-dream-dog-resource-header="sources"][class~="sticky"]::before { + background: var(--dog-coral) !important; + background-color: var(--dog-coral) !important; + background-image: var(--dog-stroke-texture) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-panel] [data-dream-dog-resource-header] [data-dream-dog-resource-add] { + display: inline-grid !important; + width: 22px !important; + height: 22px !important; + min-width: 22px !important; padding: 0 !important; - opacity: 0 !important; + place-items: center !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 52% 44% 50% 46% !important; + background: var(--dog-green) !important; + color: var(--dog-ink) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; } -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { - content: "今日委托\A\A○ 整理主题资源\A○ 调整布局骨架\A○ 验证最终效果\A○ 准备一瓶好心情"; - position: absolute; - inset: 62px 28px auto; - display: block !important; - color: #684026; - font: 650 clamp(16px, 1.8vw, 25px)/1.75 ui-rounded, "PingFang SC", sans-serif; - white-space: pre-line; - text-shadow: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-panel] [data-dream-dog-resource-header] [data-dream-dog-resource-add="sources"] { + background: var(--dog-blue) !important; } -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:nth-child(2) { +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-panel] [data-dream-dog-resource-header] [data-dream-dog-resource-add]:hover { + box-shadow: 1px 1px 0 var(--dog-ink) !important; + transform: translate(1px, 1px) rotate(9deg) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-row] { + column-gap: 8px !important; + margin: 2px 0 !important; + padding: 4px 6px !important; + border: 2px dashed transparent !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-row]:hover { + border-color: var(--dog-ink) !important; + background: #fff0a8 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-row] [data-slot="thread-summary-panel-item-leading"] { + width: 22px !important; + height: 22px !important; + margin-inline-end: 0 !important; + padding: 3px !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 5px 3px 6px 4px !important; + background: var(--dog-blue) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-row="image"] [data-slot="thread-summary-panel-item-leading"] { + background: var(--dog-green) !important; + transform: rotate(2deg) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] body [data-dream-dog-resource-view-all] { + width: fit-content !important; + padding-inline: 7px !important; + border-style: solid !important; + background: var(--dog-green) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + font-weight: 850 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-composer, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .composer-surface-chrome { position: relative !important; - z-index: 1; - grid-column: 2; - grid-row: 2; - width: auto !important; - min-width: 0 !important; - min-height: 0 !important; - padding: 0 !important; + border: var(--dog-line) !important; + border-color: var(--dog-ink) !important; + border-radius: 18px 12px 20px 14px !important; + background: + repeating-linear-gradient(4deg, rgba(255, 216, 74, .07) 0 2px, transparent 2px 9px), + var(--dog-cream) !important; + color: var(--dog-ink) !important; + box-shadow: 6px 6px 0 rgba(32, 32, 29, .92) !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*=_ComposerLayoutRoot_] { + border-top: 3px solid var(--dog-ink) !important; + background: + var(--dog-stroke-texture), + color-mix(in srgb, var(--dog-yellow) 16%, var(--dog-paper)) !important; + box-shadow: 0 -4px 0 rgba(32,32,29,.08) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*=_ComposerLayoutRoot_].dream-skin-composer-dock { + overflow: visible !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .thread-scroll-container > :where(div) > [aria-hidden="true"][class~="sticky"][class~="bottom-0"], +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .thread-scroll-container [aria-hidden="true"][class~="sticky"][class~="bottom-0"] { + background: transparent !important; + border: 0 !important; + box-shadow: none !important; + outline: 0 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .thread-scroll-container [aria-hidden="true"][class~="sticky"][class~="bottom-0"]::before, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .thread-scroll-container [aria-hidden="true"][class~="sticky"][class~="bottom-0"]::after { + content: none !important; + display: none !important; border: 0 !important; background: transparent !important; box-shadow: none !important; } -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-hero-art-name, -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-composer-stamp, -html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-washi { +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="_MainContentViewport_"] :where(div)[class~="pointer-events-none"][class~="absolute"][class~="inset-x-0"][class~="bottom-0"][class~="pb-4"] { + border: 0 !important; + outline: 0 !important; + background: transparent !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-thread-scroll-footer="true"] [aria-hidden="true"][class*="bg-gradient-to-t"] { + border: 0 !important; + outline: 0 !important; + background: transparent !important; + box-shadow: none !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-thread-scroll-footer="true"] [aria-hidden="true"][class*="bg-gradient-to-t"]::before, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-thread-scroll-footer="true"] [aria-hidden="true"][class*="bg-gradient-to-t"]::after { + content: none !important; display: none !important; } -/* Minimal focus keeps one large quiet canvas, two compact shortcuts and a - narrow composer. The artwork is contained on the right rather than cropped - into the standard banner. */ -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child { - min-height: 100% !important; - padding: 24px 34px !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [aria-hidden="true"][class~="bg-gradient-to-t"][class~="from-surface"] { + border: 0 !important; + outline: 0 !important; + background: transparent !important; + box-shadow: none !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [aria-hidden="true"][class~="bg-gradient-to-t"][class~="from-surface"]::before, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [aria-hidden="true"][class~="bg-gradient-to-t"][class~="from-surface"]::after { + content: none !important; + display: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*=_ComposerLayoutRoot_] > :not(.dream-skin-composer) { + color: var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-composer-stamp { + left: 24px !important; + bottom: 70px !important; + padding: 6px 6px 8px !important; + border: 3px solid var(--dog-ink) !important; + border-radius: 10px 7px 11px 8px !important; + background: var(--dog-yellow) !important; + box-shadow: 5px 5px 0 var(--dog-ink) !important; + opacity: 1 !important; + transform: rotate(-3deg) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-composer-stamp img { + border: 2px solid var(--dog-ink) !important; + border-radius: 7px 5px 8px 6px !important; + filter: saturate(118%) contrast(105%) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-composer-stamp span { + width: 94px !important; + max-width: 94px !important; + overflow: visible !important; + white-space: normal !important; + color: var(--dog-ink) !important; + font-family: ui-rounded, "SF Pro Rounded", "PingFang SC", system-ui, sans-serif !important; + font-style: normal !important; + font-size: 9px !important; + font-weight: 900 !important; + line-height: 1.3 !important; + text-align: center !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-composer::before, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .composer-surface-chrome::before { + content: "★" !important; + border: var(--dog-line) !important; + border-radius: 8px 6px 9px 7px !important; + background: var(--dog-coral) !important; + color: var(--dog-yellow) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-composer :where(button, [role="button"]), +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .composer-surface-chrome :where(button, [role="button"]) { + border-radius: 9px 6px 10px 7px !important; + color: var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] button[class~="bg-token-foreground"] { + border: var(--dog-line) !important; + border-radius: 10px 7px 11px 8px !important; + background: var(--dog-coral) !important; + color: #fff !important; + box-shadow: 3px 3px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(button, [role="button"]):focus-visible { + outline: 3px solid var(--dog-coral) !important; + outline-offset: 3px !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [class*=_Dialog], + [role=dialog], + [data-radix-popper-content-wrapper] > * +) { + border: var(--dog-line) !important; + border-radius: 14px 9px 15px 10px !important; + background: var(--dog-cream) !important; + color: var(--dog-ink) !important; + box-shadow: 6px 6px 0 var(--dog-ink) !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is( + [class*=_Toast], + [data-sonner-toast] +) { + border: var(--dog-line) !important; + border-radius: 12px 8px 13px 9px !important; + background: var(--dog-green) !important; + color: var(--dog-ink) !important; + box-shadow: 4px 4px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] pre, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is(code, table, [data-testid*="code"], [class*="_Terminal_"]) { + border: var(--dog-line) !important; + border-radius: 10px 6px 11px 7px !important; + background: #222725 !important; + color: #fff5d8 !important; + box-shadow: 4px 4px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :is(pre, code) :where(span) { + text-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-home > div:first-child > div:first-child > div:first-child { + border: 3px solid var(--dog-ink) !important; + border-radius: 22px 14px 24px 16px !important; + box-shadow: 7px 7px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-home [data-feature="game-source"] { + color: var(--dog-cream) !important; + font-family: ui-rounded, "SF Pro Rounded", "PingFang SC", system-ui, sans-serif !important; + text-shadow: 2px 2px 0 var(--dog-ink), -1px -1px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-home [data-feature="game-source"]::before { + border: var(--dog-line) !important; + border-radius: 999px 900px 999px 880px !important; + background: var(--dog-yellow) !important; + color: var(--dog-ink) !important; + box-shadow: 3px 3px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-home .group\/home-suggestions button { + border: var(--dog-line) !important; + border-radius: 16px 10px 18px 12px !important; + background: var(--dog-cream) !important; + color: var(--dog-ink) !important; + box-shadow: 5px 5px 0 var(--dog-ink) !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-home .group\/home-suggestions button:nth-of-type(2n) { + background: color-mix(in srgb, var(--dog-green) 22%, var(--dog-cream)) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + input, + textarea, + select, + [contenteditable="true"] +) { + color: var(--dog-ink) !important; + caret-color: var(--dog-coral) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-shell="dark"] { + --dog-ink: #151816; + --dog-paper: #202725; + --dog-cream: #2a312e; + color-scheme: dark !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-shell="dark"] body, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-shell="dark"] main.dream-skin-main-surface { + color: #fff5d8 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"][data-dream-shell="dark"] :where( + article, + [data-message-author-role], + .dream-skin-composer, + .composer-surface-chrome, + [class*="_ArtifactPanel_"], + [class*="_RightPanel_"], + [class*="_Inspector_"] +) { + border-color: #111 !important; + color: #fff5d8 !important; + box-shadow: 4px 4px 0 #111 !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] body { + background: #f7f4ee !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] body::before, +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-particles, +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-status, +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-quote, +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-hero-art-name { + display: none !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] aside.app-shell-left-panel { + border: 0 !important; + border-right: 1px solid rgba(45, 67, 91, .1) !important; + border-radius: 0 !important; + background: rgba(255, 253, 249, .96) !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(main.main-surface, main.dream-skin-main-surface), +html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) { + border: 0 !important; + border-radius: 0 !important; + background: #fbfaf7 !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(main.main-surface, main.dream-skin-main-surface) > header.app-header-tint { + border-bottom-color: rgba(45, 67, 91, .08) !important; + background: rgba(251, 250, 247, .98) !important; } html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child { - min-height: 390px !important; - flex: 1 1 auto !important; + min-height: 420px !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child > div:first-child { + border: 0 !important; + border-radius: 0 !important; + background-color: #fbfaf7 !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child > div:first-child::before { + width: 60%; + border-radius: 0; + background: linear-gradient(90deg, rgba(251, 250, 247, .98), rgba(251, 250, 247, .82) 72%, transparent) !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { + display: none !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home [data-feature="game-source"] { + color: #303235 !important; + font-size: clamp(38px, 4.2vw, 64px) !important; + letter-spacing: -.035em; + text-shadow: none; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home [data-feature="game-source"]::before { + border: 0; + border-radius: 0; + padding: 0; + background: transparent; + color: #2477ef; + box-shadow: none; + font-size: 12px; + letter-spacing: .14em; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home .group\/home-suggestions [class~="grid"] > :nth-child(n + 3) { + display: none !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home .group\/home-suggestions [class~="grid"] { + grid-template-columns: repeat(2, minmax(0, 240px)) !important; + justify-content: start !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home .group\/home-suggestions button { + min-height: 96px !important; + border-color: rgba(59, 93, 133, .12) !important; + border-radius: 18px !important; + background: #fff !important; + color: #303235 !important; + box-shadow: 0 7px 20px rgba(47, 69, 91, .06) !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(.composer-surface-chrome, .dream-skin-composer) { + width: min(72%, 820px) !important; + margin-inline: 0 auto !important; + border-color: rgba(51, 91, 137, .15) !important; + border-radius: 18px !important; + background: #fff !important; + color: #4b5056 !important; + box-shadow: 0 10px 28px rgba(48, 69, 92, .07) !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] + .dream-skin-composer[class*="_ComposerLayoutBody_"] { + width: 100% !important; + max-width: none !important; + margin-inline: 0 !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] + [class*="_ComposerLayoutBody_"] + [class*="_ComposerLayoutFooter_"] { + width: 100% !important; + max-width: none !important; + margin-inline: 0 !important; + border-color: transparent !important; + background: transparent !important; + box-shadow: none !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) :where(article, .message, [class*="surface"]:not(:is(.composer-surface-chrome, .dream-skin-composer, .dream-skin-composer-dock, .dream-skin-composer-dock *))) { + border-color: rgba(50, 85, 125, .1) !important; + background: #fff !important; + color: #303235 !important; + box-shadow: 0 8px 24px rgba(45, 66, 87, .055) !important; +} + +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) .dream-skin-composer-dock:not(.dream-skin-composer), +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) .dream-skin-composer-dock:not(.dream-skin-composer)::before, +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) .dream-skin-composer-dock:not(.dream-skin-composer)::after, +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock, +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock::before, +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock::after { + border-color: transparent !important; + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + box-shadow: none !important; + backdrop-filter: none !important; +} + +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock::before, +html.codex-dream-skin :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock::after { + content: none !important; + display: none !important; +} + +@media (max-width: 760px) { + html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child { + flex-direction: column !important; + } + + html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child, + html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:nth-child(2) { + width: 100% !important; + } + + html.codex-dream-skin[data-dream-theme="focus-capybara"] :is(.composer-surface-chrome, .dream-skin-composer) { + width: 100% !important; + } +} + +/* Dark concept themes must also override Codex's light-shell text tokens. + These tokens are attached to conversation internals rather than inherited + from :is(main.main-surface, main.dream-skin-main-surface), so setting only the shell color is insufficient. */ +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"], + [data-dream-theme="shanhai-nexus"] +) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) .thread-scroll-container { + --color-token-conversation-body: color-mix(in srgb, var(--ds-text) 94%, transparent); + --color-token-text-secondary: color-mix(in srgb, var(--ds-text) 76%, transparent); + --color-token-text-tertiary: color-mix(in srgb, var(--ds-text) 58%, transparent); + --color-token-conversation-summary-leading: color-mix(in srgb, var(--ds-text) 82%, transparent); + --color-token-conversation-summary-trailing: color-mix(in srgb, var(--ds-text) 64%, transparent); + --color-token-conversation-header: color-mix(in srgb, var(--ds-text) 68%, transparent); + --color-token-description-foreground: color-mix(in srgb, var(--ds-text) 70%, transparent); + --shimmer-text-secondary: color-mix(in srgb, var(--ds-text) 70%, transparent); + --shimmer-contrast: var(--ds-text); + color: var(--ds-text) !important; + text-shadow: none; +} + +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"], + [data-dream-theme="shanhai-nexus"] +) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) > header.app-header-tint :where(span, button, svg) { + color: var(--ds-text) !important; +} + +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"], + [data-dream-theme="shanhai-nexus"] +) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container [class*="_markdownContent_"] { + padding: 13px 15px; + border: 1px solid color-mix(in srgb, var(--ds-green) 34%, transparent); + border-radius: max(var(--ds-radius), 2px); + background: color-mix(in srgb, var(--ds-panel) 90%, transparent); + box-shadow: 0 12px 30px rgba(0, 0, 0, .22); + color: var(--ds-text) !important; +} + +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"], + [data-dream-theme="shanhai-nexus"] +) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container [class*="_markdownContent_"] + :where(p, li, h1, h2, h3, h4, h5, h6, strong, em, blockquote, span) { + color: var(--ds-text) !important; +} + +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"], + [data-dream-theme="shanhai-nexus"] +) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container [class*="_markdownContent_"] a { + color: var(--ds-lime) !important; + text-decoration-color: color-mix(in srgb, var(--ds-lime) 58%, transparent) !important; +} + +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"] +) :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container :where( + .text-token-conversation-body, + .text-token-conversation-summary-leading, + .text-token-conversation-summary-trailing, + .text-token-description-foreground, + .text-token-text-secondary, + .text-token-text-tertiary, + .group\/activity-header, + .group\/activity-header span, + .group\/activity-header svg + ) { + color: color-mix(in srgb, var(--ds-text) 78%, transparent) !important; +} + +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"], + [data-dream-theme="shanhai-nexus"] +) :is(.composer-surface-chrome, .dream-skin-composer) :where(*, .ProseMirror) { + color: var(--ds-text) !important; + caret-color: var(--ds-lime) !important; +} + +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"], + [data-dream-theme="shanhai-nexus"] +) :is(.composer-surface-chrome, .dream-skin-composer) :where([data-placeholder], [data-placeholder] *) { + color: color-mix(in srgb, var(--ds-text) 58%, transparent) !important; +} + +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"], + [data-dream-theme="shanhai-nexus"] +) .dream-skin-home [class*="_homeUtilityBar_"] { + border-color: color-mix(in srgb, var(--ds-green) 28%, transparent) !important; + background: color-mix(in srgb, var(--ds-panel) 96%, transparent) !important; + color: var(--ds-text) !important; +} + +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"], + [data-dream-theme="shanhai-nexus"] +) .dream-skin-home [class*="_homeUtilityBar_"] :where(button, span, svg) { + color: var(--ds-text) !important; +} + +/* Codex places a translucent light token layer inside the sidebar. On dark + concept themes it washed the navy/black shell into gray, so let the themed + sidebar itself provide the surface. */ +html.codex-dream-skin:is( + [data-dream-theme="neon-star-hunter"], + [data-dream-theme="hacker-zero"] +) aside.app-shell-left-panel [class*="bg-token-bg-secondary"] { + background: transparent !important; +} + +/* ------------------------------------------------------------------------- + Real split-studio composition + + The upstream Codex home page is a vertical stack (welcome area, then + banners/composer). Merely narrowing the welcome card did not create a split + layout. This grid reserves a dedicated artwork studio on the left and moves + the real Codex welcome/composer stack to the right. No fake controls are + introduced; the actual composer remains interactive. + ------------------------------------------------------------------------- */ +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child { + position: relative !important; + display: grid !important; + grid-template-columns: minmax(250px, 44%) minmax(0, 56%) !important; + grid-template-rows: minmax(0, 1fr) auto !important; + gap: 14px 18px !important; + min-height: 100% !important; + padding: 20px 22px !important; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child::before { + content: ""; + grid-column: 1; + grid-row: 1 / 3; + min-width: 0; + min-height: 0; + border: 1px solid rgba(255, 139, 38, .32); + border-radius: 26px; + background-color: #eaf7ff; + background-image: + linear-gradient(0deg, rgba(29, 59, 72, .4), transparent 42%), + var(--dream-skin-art); + background-repeat: no-repeat; + background-position: center, 8% 54%; + background-size: 100% 100%, cover; + box-shadow: 0 18px 38px rgba(57, 116, 148, .15), inset 0 0 0 1px rgba(255, 255, 255, .62); + pointer-events: none; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child { + position: relative !important; + z-index: 1; + grid-column: 2; + grid-row: 1; + min-width: 0 !important; + min-height: 0 !important; + height: auto !important; + padding: 0 !important; + align-items: stretch !important; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child { + width: 100% !important; + min-height: 0 !important; + height: auto !important; + padding: 18px !important; + border: 1px solid rgba(70, 171, 194, .2) !important; + border-radius: 24px !important; + background: rgba(255, 255, 255, .86) !important; + box-shadow: 0 14px 30px rgba(58, 117, 148, .1) !important; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child::before, +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { + display: none !important; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child > div:first-child { + min-height: 0 !important; + align-items: flex-start !important; + justify-content: flex-start !important; + padding: 0 !important; + opacity: 0 !important; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { + content: "猫猫工位已就绪\A\A扳手就位,灵感启动。\A选择一个项目,然后开始创造。"; + position: absolute; + inset: 28px 28px auto; + display: block !important; + color: #293541; + font: 700 clamp(18px, 2vw, 30px)/1.42 ui-rounded, "PingFang SC", sans-serif; + white-space: pre-line; + text-shadow: none; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child > div:nth-child(2) { + position: relative !important; + z-index: 1; + grid-column: 2; + grid-row: 2; + width: auto !important; + min-width: 0 !important; + min-height: 0 !important; + padding: 0 !important; + border: 0 !important; + background: transparent !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home [data-feature="game-source"] { + color: #293541 !important; + font-size: clamp(24px, 2.6vw, 36px) !important; + text-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home [data-feature="game-source"]::before { + border-color: rgba(73, 166, 197, .24) !important; + background: linear-gradient(100deg, rgba(74, 203, 173, .95), rgba(255, 138, 36, .92)) !important; + color: #fff !important; +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-hero-art-name { + right: auto; + top: auto; + bottom: 80px; + left: 5%; + color: rgba(255, 255, 255, .92); + text-shadow: 0 2px 12px rgba(27, 52, 63, .44); +} + +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-composer-stamp, +html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-washi { + display: none !important; +} + +@media (max-width: 760px) { + html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child { + display: flex !important; + flex-direction: column !important; + padding: 14px !important; + } + + html.codex-dream-skin[data-dream-theme="mecha-cat-studio"] .dream-skin-home > div:first-child::before { + width: 100%; + min-height: 240px; + flex: 0 0 240px; + } +} + +/* ------------------------------------------------------------------------- + Real terminal-grid composition: a dense system console occupies the left, + the agent artwork becomes a separate right module, and the real Codex + composer remains a full-width command line below. + ------------------------------------------------------------------------- */ +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child { + position: relative !important; + display: grid !important; + grid-template-columns: minmax(0, 1.55fr) minmax(210px, .72fr) !important; + grid-template-rows: minmax(0, 1fr) auto !important; + gap: 8px !important; + min-height: 100% !important; + padding: 18px !important; +} + +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child::before { + content: "ROOT@HX-0:~$ systemctl status codex-agent\A\A[ OK ] theme engine online\A[ OK ] local workspace mounted\A[ NET ] encrypted tunnel ready\A[ CPU ] 12% [ MEM ] 28%\A\A> awaiting next instruction_"; + grid-column: 1; + grid-row: 1; + min-width: 0; + min-height: 0; + padding: 34px 16px 16px; + overflow: hidden; + border: 1px solid rgba(32, 249, 118, .46); + background: + linear-gradient(rgba(30, 255, 112, .04) 1px, transparent 1px), + linear-gradient(90deg, rgba(30, 255, 112, .04) 1px, transparent 1px), + #010604; + background-size: 24px 24px; + color: #75ffae; + font: 11px/1.72 "SF Mono", Consolas, monospace; + white-space: pre-wrap; + box-shadow: inset 0 20px rgba(24, 255, 113, .035); + pointer-events: none; +} + +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child::after { + content: "[ SYSTEM LOG ] 23:47:09\A--------------------------------\A 23:47:02 handshake complete\A 23:47:04 palette verified\A 23:47:08 layout modules ready"; + grid-column: 1; + grid-row: 1; + align-self: end; + min-height: 128px; + margin: 0 8px 8px; + padding: 12px; + border: 1px solid rgba(32, 249, 118, .26); + background: rgba(1, 8, 5, .96); + color: #4fcf83; + font: 9px/1.6 "SF Mono", Consolas, monospace; + white-space: pre-wrap; + pointer-events: none; +} + +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:first-child { + position: relative !important; + z-index: 1; + grid-column: 2; + grid-row: 1; + min-width: 0 !important; + min-height: 0 !important; + height: auto !important; + padding: 0 !important; + align-items: stretch !important; +} + +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:first-child > div:first-child { + width: 100% !important; + min-height: 0 !important; + height: auto !important; + padding: 0 !important; + border: 1px solid rgba(32, 249, 118, .46) !important; + background-position: 95% center !important; + background-size: auto 100% !important; +} + +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:first-child > div:first-child::before { + width: 100% !important; + background: linear-gradient(0deg, rgba(0, 5, 2, .58), transparent 56%) !important; +} + +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:first-child > div:first-child > div:first-child { + opacity: 0 !important; +} + +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child > div:nth-child(2) { + position: relative !important; + z-index: 1; + grid-column: 1 / 3; + grid-row: 2; + width: auto !important; + min-width: 0 !important; + min-height: 0 !important; + padding: 0 !important; + border: 0 !important; + background: transparent !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-hero-art-name { + top: 92px; + right: 5%; + font: 11px/1.2 "SF Mono", Consolas, monospace; + letter-spacing: .16em; + transform: none; +} + +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-composer-stamp, +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-washi, +html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-quote { + display: none !important; +} + +/* ------------------------------------------------------------------------- + Real paper-board composition: character illustration, pinned work sheet and + the real composer form a three-column desk instead of another banner. + ------------------------------------------------------------------------- */ +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child { + position: relative !important; + display: grid !important; + grid-template-columns: minmax(220px, 36%) minmax(0, 64%) !important; + grid-template-rows: minmax(0, 1fr) auto !important; + gap: 16px !important; + min-height: 100% !important; + padding: 22px 24px !important; + background: + repeating-linear-gradient(0deg, transparent 0 25px, rgba(109, 75, 40, .045) 25px 26px), + rgba(246, 226, 184, .72); +} + +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child::before { + content: ""; + grid-column: 1; + grid-row: 1 / 3; + min-width: 0; + min-height: 0; + border: 2px solid rgba(116, 73, 34, .34); + border-radius: 42% 8px 18px 8px; + background: + linear-gradient(0deg, rgba(80, 50, 25, .35), transparent 42%), + var(--dream-skin-art) 9% 56% / cover no-repeat; + box-shadow: 6px 8px 0 rgba(101, 61, 25, .14); + pointer-events: none; +} + +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child::after { + content: "今日委托 · 配方记录"; + position: absolute; + top: 34px; + left: calc(36% + 58px); + z-index: 2; + padding: 7px 18px; + border: 1px dashed rgba(105, 66, 30, .36); + background: #f7dfae; + color: #704326; + font: 700 11px/1 ui-rounded, "PingFang SC", sans-serif; + letter-spacing: .08em; + box-shadow: 3px 4px 0 rgba(101, 61, 25, .1); + transform: rotate(-1deg); + pointer-events: none; +} + +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child { + position: relative !important; + z-index: 1; + grid-column: 2; + grid-row: 1; + min-width: 0 !important; + min-height: 0 !important; + height: auto !important; + padding: 0 !important; + align-items: stretch !important; +} + +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child { + width: 100% !important; + min-height: 0 !important; + height: auto !important; + padding: 50px 24px 20px !important; + border: 1px solid rgba(117, 74, 33, .3) !important; + border-radius: 4px 18px 4px 18px !important; + background: + repeating-linear-gradient(0deg, transparent 0 25px, rgba(114, 80, 46, .065) 25px 26px), + #fff0ca !important; + box-shadow: 5px 7px 0 rgba(101, 61, 25, .12) !important; +} + +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child::before, +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { + display: none !important; +} + +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child > div:first-child { + min-height: 0 !important; + align-items: flex-start !important; + justify-content: flex-start !important; + padding: 0 !important; + opacity: 0 !important; +} + +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:first-child > div:first-child::after { + content: "今日委托\A\A○ 整理主题资源\A○ 调整布局骨架\A○ 验证最终效果\A○ 准备一瓶好心情"; + position: absolute; + inset: 62px 28px auto; + display: block !important; + color: #684026; + font: 650 clamp(16px, 1.8vw, 25px)/1.75 ui-rounded, "PingFang SC", sans-serif; + white-space: pre-line; + text-shadow: none; +} + +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child > div:nth-child(2) { + position: relative !important; + z-index: 1; + grid-column: 2; + grid-row: 2; + width: auto !important; + min-width: 0 !important; + min-height: 0 !important; + padding: 0 !important; + border: 0 !important; + background: transparent !important; + box-shadow: none !important; +} + +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-hero-art-name, +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-composer-stamp, +html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-washi { + display: none !important; +} + +/* Minimal focus keeps one large quiet canvas, two compact shortcuts and a + narrow composer. The artwork is contained on the right rather than cropped + into the standard banner. */ +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child { + min-height: 100% !important; + padding: 24px 34px !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child { + min-height: 390px !important; + flex: 1 1 auto !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child > div:first-child { + width: 100% !important; + height: 100% !important; + min-height: 390px !important; + padding: 36px 40px !important; + background-color: transparent !important; + background-image: + linear-gradient(90deg, #fbfaf7 0 44%, rgba(251, 250, 247, .76) 58%, transparent 76%), + var(--dream-skin-art) !important; + background-repeat: no-repeat !important; + background-size: 100% 100%, contain !important; + background-position: center, right center !important; +} + +html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:nth-child(2) { + width: 68% !important; + align-self: flex-start !important; +} + +@media (max-width: 760px) { + html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child, + html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child { + display: flex !important; + flex-direction: column !important; + padding: 14px !important; + } + + html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child::before, + html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child::before { + width: 100%; + min-height: 230px; + flex: 0 0 230px; + } + + html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child::after, + html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child::after { + display: none; + } + + html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:nth-child(2) { + width: 100% !important; + } +} + +/* + * Safe native-home artwork. + * + * Non-wallpaper themes previously needed `.dream-skin-home` to expose their + * hero, but that class also opted the real Codex containers into brittle grid + * and fixed-height rewrites. Paint the artwork on the main surface instead: + * it preserves the theme identity without moving the native composer, + * suggestions, banners or project controls. + */ +html.codex-dream-skin[data-dream-native-layout="true"][data-dream-wallpaper="false"] + :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell { + background: + linear-gradient(90deg, + color-mix(in srgb, var(--ds-panel) 97%, transparent) 0%, + color-mix(in srgb, var(--ds-panel) 92%, transparent) 48%, + color-mix(in srgb, var(--ds-panel) 72%, transparent) 100%), + var(--dream-skin-art) var(--ds-hero-position) / cover no-repeat !important; +} + +/* ========================================================================== + cinematic-live + + The motion layer is injected beside the Codex shell. Native task content, + composer controls, menus and navigation remain in the original DOM. + ========================================================================== */ + +html.codex-dream-skin--cinematic-live { + color-scheme: dark !important; +} + +html.codex-dream-skin--cinematic-live body { + background: #03070a !important; + color: #eef8f7 !important; +} + +html.codex-dream-skin--cinematic-live body::before { + display: none !important; +} + +#codex-dream-skin-motion { + position: fixed; + z-index: 0; + overflow: hidden; + pointer-events: none; + background: #03070a; +} + +.dream-skin-cinematic-poster, +.dream-skin-cinematic-video, +.dream-skin-cinematic-shade { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} + +.dream-skin-cinematic-poster { + background-color: #03070a; + background-position: center center; + background-repeat: no-repeat; + background-size: cover; +} + +.dream-skin-cinematic-video { + z-index: 1; + display: block; + border: 0; + object-fit: cover; + object-position: center center; + opacity: 1; +} + +.dream-skin-cinematic-shade { + z-index: 2; + background: rgba(1, 6, 9, .14); + box-shadow: + inset 180px 0 180px rgba(1, 6, 9, .28), + inset 0 80px 90px rgba(1, 5, 8, .22); +} + +#codex-dream-skin-motion[data-motion-error="true"] .dream-skin-cinematic-video { + display: none; +} + +#codex-dream-skin-cinematic-ui { + position: fixed; + z-index: 4; + overflow: hidden; + pointer-events: none; + color: rgba(235, 247, 246, .94); + font-family: "SF Pro Text", "PingFang SC", system-ui, sans-serif; +} + +html.codex-dream-skin--cinematic-live #root :has(> :is(main.main-surface, main.dream-skin-main-surface)) { + position: relative; + z-index: 1; +} + +.dream-skin-cinematic-topline { + position: absolute; + top: 18px; + left: 24px; + right: 24px; + display: flex; + align-items: center; + justify-content: space-between; + min-height: 22px; + padding-bottom: 10px; + border-bottom: 1px solid rgba(142, 211, 202, .14); + color: rgba(220, 240, 237, .64); + font-size: 9px; + font-weight: 650; + letter-spacing: .22em; + text-transform: uppercase; +} + +.dream-skin-cinematic-topline span { + display: inline-flex; + align-items: center; + gap: 7px; +} + +.dream-skin-cinematic-topline span i { + width: 5px; + height: 5px; + border-radius: 999px; + background: #8be0d2; + box-shadow: 0 0 12px rgba(115, 224, 207, .86); +} + +.dream-skin-cinematic-topline b { + color: rgba(220, 240, 237, .44); + font-size: 8px; + font-weight: 600; + letter-spacing: .18em; +} + +.dream-skin-cinematic-transcript { + position: absolute; + left: clamp(42px, 7vw, 104px); + top: 26%; + width: min(39%, 520px); + min-height: 120px; + padding: 22px 24px; + border: 1px solid rgba(139, 213, 202, .18); + background: rgba(3, 10, 14, .48); + box-shadow: + 0 24px 80px rgba(0, 0, 0, .2), + inset 0 1px rgba(255, 255, 255, .03); + backdrop-filter: blur(18px) saturate(112%); +} + +.dream-skin-cinematic-transcript small { + display: block; + margin-bottom: 30px; + color: rgba(133, 213, 201, .7); + font-size: 8px; + font-weight: 700; + letter-spacing: .22em; +} + +.dream-skin-cinematic-transcript p { + margin: 0; + color: rgba(235, 246, 244, .78); + font-size: clamp(12px, 1.08vw, 15px); + font-weight: 430; + line-height: 1.8; + letter-spacing: .035em; +} + +.dream-skin-cinematic-actions { + position: absolute; + left: clamp(72px, 13vw, 188px); + bottom: 18%; + display: flex; + align-items: center; + gap: 20px; + pointer-events: auto; +} + +.dream-skin-cinematic-actions button { + appearance: none; + cursor: pointer; + color: rgba(231, 247, 244, .86); + border: 1px solid rgba(139, 220, 207, .28); + background: rgba(4, 14, 18, .52); + font: 600 10px/1 "SF Pro Text", "PingFang SC", system-ui, sans-serif; + letter-spacing: .12em; + backdrop-filter: blur(16px); + transition: border-color .18s ease, background .18s ease, transform .18s ease; +} + +.dream-skin-cinematic-actions button:hover, +.dream-skin-cinematic-actions button:focus-visible { + border-color: rgba(151, 235, 221, .72); + background: rgba(11, 35, 38, .72); + transform: translateY(-2px); + outline: none; +} + +.dream-skin-cinematic-actions [data-cinematic-action="start"] { + width: 108px; + height: 108px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 11px; + border-radius: 999px; + box-shadow: + 0 0 0 8px rgba(108, 217, 199, .025), + 0 0 42px rgba(91, 220, 200, .12), + inset 0 0 28px rgba(93, 216, 198, .06); +} + +.dream-skin-cinematic-actions [data-cinematic-action="start"] i { + color: rgba(154, 221, 210, .54); + font-size: 7px; + font-style: normal; + letter-spacing: .2em; +} + +.dream-skin-cinematic-actions [data-cinematic-action="replay"] { + padding: 9px 12px; + border-radius: 999px; + color: rgba(199, 229, 224, .56); + font-size: 8px; +} + +#codex-dream-skin-cinematic-ui.is-task .dream-skin-cinematic-transcript, +#codex-dream-skin-cinematic-ui.is-task .dream-skin-cinematic-actions { + display: none; +} + +html.codex-dream-skin--cinematic-live aside.app-shell-left-panel { + position: relative; + z-index: 5; + border-color: rgba(130, 198, 190, .12) !important; + border-radius: 0 !important; + background: rgba(3, 9, 12, .92) !important; + box-shadow: 12px 0 42px rgba(0, 0, 0, .32) !important; + backdrop-filter: blur(22px) saturate(105%) !important; +} + +html.codex-dream-skin--cinematic-live aside.app-shell-left-panel :where(button, a, span, div) { + color: rgba(219, 235, 233, .72) !important; +} + +html.codex-dream-skin--cinematic-live aside.app-shell-left-panel svg { + color: rgba(139, 213, 202, .62) !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface) { + position: relative; + z-index: 1; + border: 0 !important; + border-radius: 0 !important; + background: rgba(1, 6, 9, .05) !important; + box-shadow: none !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell { + --color-token-side-bar-background: rgba(3, 12, 16, .7); + --color-token-bg-fog: rgba(3, 12, 16, .78); + --color-token-dropdown-background: rgba(4, 14, 18, .94); + --color-token-list-hover-background: rgba(139, 213, 202, .1); + --color-token-input-background: rgba(3, 12, 16, .7); + --color-token-border: rgba(139, 213, 202, .18); + --color-token-foreground: rgba(236, 248, 246, .94); + --color-token-text-primary: rgba(236, 248, 246, .92); + --color-token-text-secondary: rgba(221, 239, 236, .72); + --color-token-text-tertiary: rgba(205, 228, 224, .56); + --color-text-foreground: rgba(236, 248, 246, .92); +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell + [class*="bg-token-side-bar-background"] { + border: 1px solid rgba(139, 213, 202, .16) !important; + border-bottom: 0 !important; + background: rgba(3, 12, 16, .7) !important; + box-shadow: inset 0 1px rgba(255, 255, 255, .03) !important; + color: rgba(230, 244, 242, .78) !important; + backdrop-filter: blur(22px) saturate(108%) !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) { + --color-token-bg-fog: rgba(4, 14, 18, .76); + --color-token-dropdown-background: rgba(4, 14, 18, .92); + --color-token-input-background: rgba(4, 14, 18, .82); + --color-token-border: rgba(139, 213, 202, .18); + --color-token-foreground: rgba(236, 248, 246, .94); + --color-background-control: rgba(4, 14, 18, .76); + --color-background-control-opaque: rgb(4, 14, 18); + --color-background-elevated-primary: rgba(4, 14, 18, .92); + --color-background-elevated-primary-opaque: rgb(4, 14, 18); + --color-background-elevated-secondary: rgba(7, 22, 26, .9); + --color-background-elevated-secondary-opaque: rgb(7, 22, 26); + background: rgba(1, 6, 9, .14) !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface) :is([role="main"], .dream-skin-role-main) { + background: transparent !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell + .group\/home-suggestions { + max-height: 0 !important; + margin: 0 !important; + overflow: hidden !important; + opacity: 0 !important; + pointer-events: none !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell + [data-feature="game-source"] { + opacity: 0 !important; + pointer-events: none !important; +} + +html.codex-dream-skin--cinematic-live :is(.composer-surface-chrome, .dream-skin-composer) { + width: min(58vw, 670px) !important; + max-width: calc(100% - 56px) !important; + margin-right: auto !important; + margin-left: clamp(28px, 6vw, 88px) !important; + border: 1px solid rgba(139, 213, 202, .24) !important; + border-radius: 22px !important; + background: rgba(3, 12, 16, .62) !important; + box-shadow: + 0 24px 68px rgba(0, 0, 0, .28), + inset 0 1px rgba(255, 255, 255, .04) !important; + color: rgba(234, 246, 244, .92) !important; + backdrop-filter: blur(24px) saturate(108%) !important; +} + +html.codex-dream-skin--cinematic-live :is(.composer-surface-chrome, .dream-skin-composer)::before { + display: none !important; +} + +html.codex-dream-skin--cinematic-live :is(.composer-surface-chrome, .dream-skin-composer) :where(*, .ProseMirror) { + color: rgba(230, 243, 241, .88) !important; + caret-color: #8be0d2 !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container { + width: min(61%, 780px) !important; + margin-right: auto !important; + margin-left: clamp(18px, 4vw, 58px) !important; + background: transparent !important; + --color-text-foreground: rgba(236, 248, 246, .94); + --color-text-foreground-secondary: rgba(221, 239, 236, .74); + --color-text-foreground-tertiary: rgba(205, 228, 224, .58); + --color-icon-primary: rgba(236, 248, 246, .92); + --color-icon-secondary: rgba(213, 235, 231, .68); + --color-icon-tertiary: rgba(195, 224, 219, .52); + --color-token-conversation-body: rgba(236, 248, 246, .94); + --color-token-text-secondary: rgba(221, 239, 236, .74); + --color-token-text-tertiary: rgba(205, 228, 224, .58); + --color-token-conversation-summary-leading: rgba(230, 244, 242, .84); + --color-token-conversation-summary-trailing: rgba(210, 233, 229, .64); + --color-token-conversation-header: rgba(213, 235, 231, .68); + --color-token-description-foreground: rgba(216, 236, 233, .7); + --shimmer-text-secondary: rgba(216, 236, 233, .7); + --shimmer-contrast: #edf8f6; + color: rgba(236, 248, 246, .94) !important; + text-shadow: none; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container :where( + .text-token-foreground, + .text-token-conversation-body, + .text-token-conversation-summary-leading, + .text-token-conversation-summary-trailing, + .text-token-description-foreground, + .text-token-text-secondary, + .text-token-text-tertiary, + .group\/activity-header, + .group\/activity-header span, + .group\/activity-header svg + ) { + color: rgba(226, 242, 239, .84) !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container [class*="_markdownContent_"] { + padding: 13px 15px; + border: 1px solid rgba(139, 213, 202, .16); + border-radius: 14px; + background: rgba(3, 11, 15, .58); + box-shadow: 0 18px 50px rgba(0, 0, 0, .22); + color: rgba(236, 248, 246, .94) !important; + backdrop-filter: blur(20px) saturate(108%); +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container [class*="_markdownContent_"] + :where(p, li, h1, h2, h3, h4, h5, h6, strong, em, blockquote, span) { + color: rgba(236, 248, 246, .94) !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container [class*="_markdownContent_"] a { + color: #8be0d2 !important; + text-decoration-color: rgba(139, 224, 210, .56) !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + :where(article, .message, [data-message-author-role]) { + border: 1px solid rgba(139, 213, 202, .16) !important; + background: rgba(3, 11, 15, .58) !important; + box-shadow: 0 18px 50px rgba(0, 0, 0, .22) !important; + color: rgba(233, 246, 244, .9) !important; + backdrop-filter: blur(20px) saturate(108%) !important; +} + +html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + [data-message-author-role="user"] { + border-color: rgba(122, 217, 201, .28) !important; + background: rgba(26, 83, 77, .66) !important; +} + +html.codex-dream-skin--cinematic-live :where(pre, code, table, [data-testid*="code"]) { + border-color: rgba(139, 213, 202, .16) !important; + background: rgba(1, 7, 10, .8) !important; + color: #cfe5e1 !important; +} + +html.codex-dream-skin--cinematic-live :where([role="dialog"], [role="menu"], [role="listbox"], [role="tooltip"]) { + border-color: rgba(139, 213, 202, .22) !important; + background: rgba(4, 13, 17, .96) !important; + color: #e9f6f4 !important; + box-shadow: 0 24px 70px rgba(0, 0, 0, .42) !important; +} + +@media (max-width: 1100px) { + .dream-skin-cinematic-transcript { + left: 38px; + width: 45%; + } + + .dream-skin-cinematic-actions { + left: 78px; + } + + html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container { + width: 68% !important; + margin-left: 18px !important; + } +} + +@media (max-width: 899px) { + .dream-skin-cinematic-video { + display: none !important; + } + + .dream-skin-cinematic-poster { + background-position: 68% center; + } + + .dream-skin-cinematic-transcript { + left: 24px; + width: calc(100% - 48px); + max-width: 520px; + } + + .dream-skin-cinematic-actions { + left: 48px; + } + + html.codex-dream-skin--cinematic-live :is(.composer-surface-chrome, .dream-skin-composer), + html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) + .thread-scroll-container { + width: calc(100% - 32px) !important; + max-width: none !important; + margin-right: 16px !important; + margin-left: 16px !important; + } +} + +@media (prefers-reduced-motion: reduce) { + .dream-skin-cinematic-video { + display: none !important; + } + + .dream-skin-cinematic-actions button { + transition: none; + } +} + +/* Happy Coding Dog — conversation narrative and edit cards */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"] { + position: relative !important; + margin: 6px 0 15px !important; + padding: 17px 19px 18px 24px !important; + border: 3px solid var(--dog-marker-shadow) !important; + border-radius: 15px 10px 17px 11px !important; + background: + linear-gradient(90deg, var(--dog-marker-blue) 0 10px, transparent 10px), + repeating-linear-gradient(-3deg, rgba(255,216,74,.07) 0 2px, transparent 2px 9px), + #fffaf0 !important; + box-shadow: 7px 7px 0 var(--dog-marker-shadow) !important; + transform: rotate(-.06deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"]::before { + content: "✦" !important; + position: absolute !important; + top: -12px !important; + left: 16px !important; + display: grid !important; + width: 25px !important; + height: 25px !important; + place-items: center !important; + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 48% 52% 43% 57% !important; + background: var(--dog-marker-red) !important; + color: #fff9e8 !important; + font-size: 14px !important; + line-height: 1 !important; + box-shadow: 2px 2px 0 var(--dog-marker-shadow) !important; + transform: rotate(-7deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"] > :first-child { + font-weight: 900 !important; + text-decoration: underline !important; + text-decoration-color: var(--dog-marker-red) !important; + text-decoration-thickness: 3px !important; + text-underline-offset: 5px !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"] :where(ul, ol) { + padding-left: 1.45rem !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"] li::marker { + color: var(--dog-marker-red) !important; + font-size: 1.15em !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] { + position: relative !important; + overflow: hidden !important; + border: 3px solid var(--dog-marker-shadow) !important; + border-radius: 13px 9px 15px 10px !important; + background: + linear-gradient(to right, var(--dog-marker-green) 0 12px, transparent 12px), + repeating-linear-gradient(3deg, rgba(23,111,168,.045) 0 2px, transparent 2px 9px), + #fffaf0 !important; + box-shadow: 7px 7px 0 var(--dog-marker-shadow) !important; + transform: rotate(.04deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] [class*="group/turn-diff-header"] { + background: + linear-gradient(90deg, rgba(120,198,75,.18), transparent 58%), + transparent !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] :where(button, [role="button"]) { + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 8px 6px 9px 7px !important; + background: var(--dog-marker-yellow) !important; + color: var(--dog-marker-shadow) !important; + font-weight: 850 !important; + box-shadow: 2px 2px 0 var(--dog-marker-shadow) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] :where(svg) { + color: var(--dog-marker-blue) !important; + stroke-width: 2.2 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-local-conversation-final-assistant="true"] > :last-child :where(button, [role="button"]) { + border-radius: 7px 5px 8px 6px !important; + color: var(--dog-marker-blue) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-in-progress-fixed-content="true"] [class*="overflow-hidden"]:has([class*="bg-background-primary-soft/70"]) { + overflow: visible !important; + border-radius: 0 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-in-progress-fixed-content="true"] [class*="bg-background-primary-soft/70"] { + position: relative !important; + min-height: 37px !important; + padding: 6px 14px 7px 34px !important; + overflow: visible !important; + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 12px 8px 13px 9px !important; + background: + repeating-linear-gradient(-4deg, rgba(255,255,255,.12) 0 2px, transparent 2px 8px), + var(--dog-marker-yellow) !important; + color: var(--dog-marker-shadow) !important; + font-weight: 850 !important; + box-shadow: 4px 4px 0 var(--dog-marker-shadow) !important; + backdrop-filter: none !important; + transform: rotate(-.35deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-in-progress-fixed-content="true"] [class*="bg-background-primary-soft/70"]::before { + content: "✎" !important; + position: absolute !important; + top: 5px !important; + left: 7px !important; + display: grid !important; + width: 22px !important; + height: 22px !important; + place-items: center !important; + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 50% 45% 53% 47% !important; + background: var(--dog-marker-red) !important; + color: #fff9e8 !important; + font-size: 13px !important; + line-height: 1 !important; + transform: rotate(-7deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-in-progress-fixed-content="true"] [class*="bg-background-primary-soft/70"] :where(.text-success, [class*="text-success"]) { + color: var(--dog-marker-blue) !important; + font-weight: 900 !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:first-child > div:first-child { - width: 100% !important; - height: 100% !important; - min-height: 390px !important; - padding: 36px 40px !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="_MainContentViewport_"] .thread-scroll-container > div [aria-hidden="true"][class~="bg-gradient-to-t"][class~="from-surface"][class~="via-surface"] { + background: transparent !important; background-color: transparent !important; - background-image: - linear-gradient(90deg, #fbfaf7 0 44%, rgba(251, 250, 247, .76) 58%, transparent 76%), - var(--dream-skin-art) !important; - background-repeat: no-repeat !important; - background-size: 100% 100%, contain !important; - background-position: center, right center !important; + background-image: none !important; + border: 0 !important; + box-shadow: none !important; + opacity: 0 !important; } -html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:nth-child(2) { - width: 68% !important; - align-self: flex-start !important; +/* Happy Coding Dog — broader acrylic colour composition */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-pip-anchor-host="codex-main-thread"].thread-scroll-container { + background: + radial-gradient(ellipse 240px 150px at 12% 25%, rgba(35,183,201,.105), transparent 72%), + radial-gradient(ellipse 280px 170px at 84% 36%, rgba(240,79,61,.085), transparent 74%), + radial-gradient(ellipse 250px 180px at 25% 78%, rgba(120,198,75,.095), transparent 72%), + radial-gradient(ellipse 210px 140px at 76% 88%, rgba(255,216,74,.16), transparent 74%) !important; } -@media (max-width: 760px) { - html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child, - html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child { - display: flex !important; - flex-direction: column !important; - padding: 14px !important; - } - - html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child::before, - html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child::before { - width: 100%; - min-height: 230px; - flex: 0 0 230px; - } - - html.codex-dream-skin[data-dream-theme="hacker-zero"] .dream-skin-home > div:first-child::after, - html.codex-dream-skin[data-dream-theme="potion-workshop"] .dream-skin-home > div:first-child::after { - display: none; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"] { + background: + linear-gradient(90deg, var(--dog-marker-blue) 0 10px, transparent 10px), + repeating-linear-gradient(-3deg, rgba(255,255,255,.13) 0 2px, transparent 2px 9px), + color-mix(in srgb, #8eddea 30%, #fffaf0) !important; +} - html.codex-dream-skin[data-dream-theme="focus-capybara"] .dream-skin-home > div:first-child > div:nth-child(2) { - width: 100% !important; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"]::after { + content: "" !important; + position: absolute !important; + top: -3px !important; + right: 24px !important; + width: 68px !important; + height: 17px !important; + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 4px 8px 3px 7px !important; + background: + repeating-linear-gradient(5deg, rgba(255,255,255,.14) 0 2px, transparent 2px 7px), + var(--dog-marker-yellow) !important; + box-shadow: 2px 2px 0 var(--dog-marker-shadow) !important; + transform: rotate(1.7deg); } -/* - * Safe native-home artwork. - * - * Non-wallpaper themes previously needed `.dream-skin-home` to expose their - * hero, but that class also opted the real Codex containers into brittle grid - * and fixed-height rewrites. Paint the artwork on the main surface instead: - * it preserves the theme identity without moving the native composer, - * suggestions, banners or project controls. - */ -html.codex-dream-skin[data-dream-native-layout="true"][data-dream-wallpaper="false"] - :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell { +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-message-author-role="user"] { background: - linear-gradient(90deg, - color-mix(in srgb, var(--ds-panel) 97%, transparent) 0%, - color-mix(in srgb, var(--ds-panel) 92%, transparent) 48%, - color-mix(in srgb, var(--ds-panel) 72%, transparent) 100%), - var(--dream-skin-art) var(--ds-hero-position) / cover no-repeat !important; + repeating-linear-gradient(4deg, rgba(255,255,255,.13) 0 2px, transparent 2px 8px), + color-mix(in srgb, var(--dog-marker-red) 24%, var(--dog-marker-yellow)) !important; + box-shadow: 5px 5px 0 var(--dog-marker-blue) !important; } -/* ========================================================================== - cinematic-live +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] > :nth-child(n + 2):nth-child(3n + 1), +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] [class*="turn-diff-row"]:nth-of-type(3n + 1) { + background: color-mix(in srgb, var(--dog-marker-green) 22%, #fffaf0) !important; +} - The motion layer is injected beside the Codex shell. Native task content, - composer controls, menus and navigation remain in the original DOM. - ========================================================================== */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] > :nth-child(n + 2):nth-child(3n + 2), +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] [class*="turn-diff-row"]:nth-of-type(3n + 2) { + background: color-mix(in srgb, #8eddea 24%, #fffaf0) !important; +} -html.codex-dream-skin--cinematic-live { - color-scheme: dark !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] > :nth-child(n + 2):nth-child(3n), +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] [class*="turn-diff-row"]:nth-of-type(3n) { + background: color-mix(in srgb, var(--dog-marker-red) 13%, #fffaf0) !important; } -html.codex-dream-skin--cinematic-live body { - background: #03070a !important; - color: #eef8f7 !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) [class*="items-center"]:has(> button) { + border-radius: 8px 6px 10px 7px !important; + background: + linear-gradient(90deg, rgba(255,216,74,.15), rgba(120,198,75,.12) 45%, rgba(35,183,201,.11)) !important; } -html.codex-dream-skin--cinematic-live body::before { - display: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button:nth-of-type(3n + 1) { + color: var(--dog-marker-red) !important; } -#codex-dream-skin-motion { - position: fixed; - z-index: 0; - overflow: hidden; - pointer-events: none; - background: #03070a; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button:nth-of-type(3n + 2) { + color: var(--dog-marker-blue) !important; } -.dream-skin-cinematic-poster, -.dream-skin-cinematic-video, -.dream-skin-cinematic-shade { - position: absolute; - inset: 0; - width: 100%; - height: 100%; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button:nth-of-type(3n) { + color: #4f8f2d !important; } -.dream-skin-cinematic-poster { - background-color: #03070a; - background-position: center center; - background-repeat: no-repeat; - background-size: cover; +/* Happy Coding Dog — composer control illustrations */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button[data-composer-navigation-target="add-context"] { + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 9px 7px 10px 8px !important; + background: var(--dog-marker-yellow) !important; + color: var(--dog-marker-blue) !important; + box-shadow: 2px 2px 0 var(--dog-marker-shadow) !important; + transform: rotate(-1.5deg); } -.dream-skin-cinematic-video { - z-index: 1; - display: block; - border: 0; - object-fit: cover; - object-position: center center; - opacity: 1; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button[data-composer-navigation-target="permissions"] { + min-height: 28px !important; + padding-inline: 9px !important; + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 9px 12px 8px 11px !important; + background: color-mix(in srgb, var(--dog-marker-red) 18%, var(--dog-marker-cream)) !important; + color: var(--dog-marker-red) !important; + font-weight: 850 !important; + box-shadow: 2px 2px 0 var(--dog-marker-red) !important; + transform: rotate(.35deg); } -.dream-skin-cinematic-shade { - z-index: 2; - background: rgba(1, 6, 9, .14); - box-shadow: - inset 180px 0 180px rgba(1, 6, 9, .28), - inset 0 80px 90px rgba(1, 5, 8, .22); +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button[data-composer-navigation-target="reasoning"] { + min-height: 29px !important; + padding-inline: 10px !important; + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 11px 8px 12px 9px !important; + background: + repeating-linear-gradient(4deg, rgba(255,255,255,.08) 0 2px, transparent 2px 8px), + var(--dog-marker-blue) !important; + color: #fff9e8 !important; + font-weight: 850 !important; + box-shadow: 3px 3px 0 var(--dog-marker-shadow) !important; + margin-right: 9px !important; + transform: rotate(-.3deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button[data-composer-navigation-target="reasoning"] :where(svg, span) { + color: #fff9e8 !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button[aria-label="听写"] { + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 48% 52% 44% 56% !important; + background: var(--dog-marker-green) !important; + color: var(--dog-marker-shadow) !important; + box-shadow: 2px 2px 0 var(--dog-marker-shadow) !important; + transform: rotate(1.5deg); +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button:is([aria-label="发送"], [aria-label="停止"]) { + border: 2px solid var(--dog-marker-shadow) !important; + border-radius: 10px 7px 11px 8px !important; + background: var(--dog-marker-red) !important; + color: #fff9e8 !important; + box-shadow: 3px 3px 0 var(--dog-marker-shadow) !important; + transform: rotate(-1deg); } -#codex-dream-skin-motion[data-motion-error="true"] .dream-skin-cinematic-video { - display: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) :where([class*="animate-spin"], [data-loading="true"]) { + border-radius: 50% !important; + color: var(--dog-marker-red) !important; + filter: drop-shadow(1px 1px 0 var(--dog-marker-yellow)) !important; } -#codex-dream-skin-cinematic-ui { - position: fixed; - z-index: 4; - overflow: hidden; - pointer-events: none; - color: rgba(235, 247, 246, .94); - font-family: "SF Pro Text", "PingFang SC", system-ui, sans-serif; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where(.composer-surface-chrome, .dream-skin-composer) button:not([disabled]):active { + box-shadow: 1px 1px 0 var(--dog-marker-shadow) !important; + translate: 1px 1px; } -html.codex-dream-skin--cinematic-live #root :has(> :is(main.main-surface, main.dream-skin-main-surface)) { - position: relative; - z-index: 1; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-codex-composer-root] [class~="bg-gradient-to-t"][class~="from-surface"][class~="to-transparent"] { + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + border: 0 !important; + box-shadow: none !important; + opacity: 0 !important; } -.dream-skin-cinematic-topline { - position: absolute; - top: 18px; - left: 24px; - right: 24px; - display: flex; - align-items: center; - justify-content: space-between; - min-height: 22px; - padding-bottom: 10px; - border-bottom: 1px solid rgba(142, 211, 202, .14); - color: rgba(220, 240, 237, .64); - font-size: 9px; - font-weight: 650; - letter-spacing: .22em; - text-transform: uppercase; +/* Happy Coding Dog — responsive narrow conversation pane */ +@container thread-content (max-width: 560px) { + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"] { + margin-block: 4px 11px !important; + padding: 11px 11px 12px 17px !important; + border-width: 2px !important; + border-radius: 11px 7px 12px 8px !important; + font-size: 13px !important; + line-height: 1.48 !important; + box-shadow: 4px 4px 0 var(--dog-marker-shadow) !important; + } + + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"]::before { + top: -9px !important; + left: 10px !important; + width: 20px !important; + height: 20px !important; + font-size: 11px !important; + } + + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"]::after { + right: 14px !important; + width: 48px !important; + height: 12px !important; + } + + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] { + border-width: 2px !important; + border-radius: 10px 7px 11px 8px !important; + font-size: 12px !important; + box-shadow: 4px 4px 0 var(--dog-marker-shadow) !important; + } + + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [class*="--turn-diff-row-padding-y"] :where(button, [role="button"]) { + min-width: 0 !important; + padding-inline: 6px !important; + font-size: 12px !important; + } + + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-codex-composer-root] { + min-width: 0 !important; + } + + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-composer { + border-width: 2px !important; + border-radius: 13px 9px 14px 10px !important; + box-shadow: 4px 4px 0 var(--dog-marker-shadow) !important; + } + + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-composer button[data-composer-navigation-target="permissions"] { + max-width: 76px !important; + padding-inline: 6px !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + } + + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] .dream-skin-composer button[data-composer-navigation-target="reasoning"] { + max-width: 112px !important; + padding-inline: 7px !important; + margin-right: 6px !important; + overflow: hidden !important; + } + + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-in-progress-fixed-content="true"] [class*="bg-background-primary-soft/70"] { + max-width: calc(100% - 20px) !important; + min-height: 32px !important; + padding: 4px 9px 5px 29px !important; + font-size: 12px !important; + box-shadow: 3px 3px 0 var(--dog-marker-shadow) !important; + } } -.dream-skin-cinematic-topline span { - display: inline-flex; - align-items: center; - gap: 7px; +/* Happy Coding Dog — review / diff workspace */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + [class*="Review"], + [class*="review"], + [data-testid*="review"], + [aria-label*="审查"] +) { + --review-paper: #fffaf0; + --review-line: #20201d; + color: var(--dog-marker-shadow) !important; } -.dream-skin-cinematic-topline span i { - width: 5px; - height: 5px; - border-radius: 999px; - background: #8be0d2; - box-shadow: 0 0 12px rgba(115, 224, 207, .86); +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where([role="tablist"], [class*="TabList"], [class*="tab-list"]) { + gap: 7px !important; + padding: 6px 9px !important; + border-bottom: 3px solid var(--dog-marker-shadow) !important; + background: + repeating-linear-gradient(3deg, rgba(255,255,255,.1) 0 2px, transparent 2px 8px), + var(--dog-marker-yellow) !important; } -.dream-skin-cinematic-topline b { - color: rgba(220, 240, 237, .44); - font-size: 8px; - font-weight: 600; - letter-spacing: .18em; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where([role="tab"], [class*="TabButton"], [class*="tab-button"]) { + min-height: 31px !important; + padding: 4px 11px !important; + border: 2px solid transparent !important; + border-radius: 9px 6px 10px 7px !important; + color: var(--dog-marker-shadow) !important; + font-weight: 850 !important; } -.dream-skin-cinematic-transcript { - position: absolute; - left: clamp(42px, 7vw, 104px); - top: 26%; - width: min(39%, 520px); - min-height: 120px; - padding: 22px 24px; - border: 1px solid rgba(139, 213, 202, .18); - background: rgba(3, 10, 14, .48); - box-shadow: - 0 24px 80px rgba(0, 0, 0, .2), - inset 0 1px rgba(255, 255, 255, .03); - backdrop-filter: blur(18px) saturate(112%); +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where([role="tab"][aria-selected="true"], [role="tab"][data-state="active"]) { + border-color: var(--dog-marker-shadow) !important; + background: var(--dog-marker-cream) !important; + box-shadow: 3px 3px 0 var(--dog-marker-red) !important; + transform: rotate(-.35deg); } -.dream-skin-cinematic-transcript small { - display: block; - margin-bottom: 30px; - color: rgba(133, 213, 201, .7); - font-size: 8px; - font-weight: 700; - letter-spacing: .22em; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + .monaco-editor, + .cm-editor, + [class*="DiffEditor"], + [class*="diff-editor"], + [data-testid*="diff-view"] +) { + border: 3px solid var(--dog-marker-shadow) !important; + border-radius: 12px 8px 13px 9px !important; + background: var(--review-paper, #fffaf0) !important; + box-shadow: 6px 6px 0 var(--dog-marker-shadow) !important; + overflow: hidden !important; } -.dream-skin-cinematic-transcript p { - margin: 0; - color: rgba(235, 246, 244, .78); - font-size: clamp(12px, 1.08vw, 15px); - font-weight: 430; - line-height: 1.8; - letter-spacing: .035em; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + .monaco-editor .margin, + .cm-gutters, + [class*="line-numbers"], + [class*="LineNumber"] +) { + border-right: 2px solid var(--dog-marker-shadow) !important; + background: color-mix(in srgb, #8eddea 31%, #fffaf0) !important; + color: var(--dog-marker-blue) !important; + font-weight: 800 !important; } -.dream-skin-cinematic-actions { - position: absolute; - left: clamp(72px, 13vw, 188px); - bottom: 18%; - display: flex; - align-items: center; - gap: 20px; - pointer-events: auto; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + .monaco-editor .view-line, + .cm-line, + [class*="DiffLine"], + [data-testid*="diff-line"] +) { + border-bottom: 1px solid rgba(32,32,29,.055) !important; + font-family: "SFMono-Regular", Menlo, Monaco, Consolas, monospace !important; } -.dream-skin-cinematic-actions button { - appearance: none; - cursor: pointer; - color: rgba(231, 247, 244, .86); - border: 1px solid rgba(139, 220, 207, .28); - background: rgba(4, 14, 18, .52); - font: 600 10px/1 "SF Pro Text", "PingFang SC", system-ui, sans-serif; - letter-spacing: .12em; - backdrop-filter: blur(16px); - transition: border-color .18s ease, background .18s ease, transform .18s ease; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + .line-insert, + .char-insert, + [class*="added-line"], + [data-diff-type="addition"] +) { + background: color-mix(in srgb, var(--dog-marker-green) 31%, #fffaf0) !important; + box-shadow: inset 4px 0 0 #35a853 !important; } -.dream-skin-cinematic-actions button:hover, -.dream-skin-cinematic-actions button:focus-visible { - border-color: rgba(151, 235, 221, .72); - background: rgba(11, 35, 38, .72); - transform: translateY(-2px); - outline: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + .line-delete, + .char-delete, + [class*="removed-line"], + [data-diff-type="deletion"] +) { + background: color-mix(in srgb, var(--dog-marker-red) 22%, #fffaf0) !important; + box-shadow: inset 4px 0 0 var(--dog-marker-red) !important; } -.dream-skin-cinematic-actions [data-cinematic-action="start"] { - width: 108px; - height: 108px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 11px; - border-radius: 999px; - box-shadow: - 0 0 0 8px rgba(108, 217, 199, .025), - 0 0 42px rgba(91, 220, 200, .12), - inset 0 0 28px rgba(93, 216, 198, .06); +/* Happy Coding Dog — native new-task surface only. Keep task/thread pages untouched. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell { + background: + radial-gradient(circle at 12% 18%, rgba(42,177,197,.24) 0 4px, transparent 5px), + radial-gradient(circle at 82% 26%, rgba(255,91,73,.22) 0 4px, transparent 5px), + radial-gradient(circle at 68% 72%, rgba(136,201,63,.22) 0 5px, transparent 6px), + repeating-linear-gradient(3deg, rgba(255,216,74,.08) 0 2px, transparent 2px 9px), + var(--dog-paper) !important; +} + +/* The native home composer has several full-width layout wrappers. They must + stay transparent; only the actual input card receives the painted frame. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class*="_ComposerLayoutRoot_"], +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class*="_ComposerLayoutRoot_"].dream-skin-composer-dock, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [class*="_ComposerLayoutRoot_"] > :not(.dream-skin-composer) { + border: 0 !important; + outline: 0 !important; + background: transparent !important; + box-shadow: none !important; + transform: none !important; } -.dream-skin-cinematic-actions [data-cinematic-action="start"] i { - color: rgba(154, 221, 210, .54); - font-size: 7px; - font-style: normal; - letter-spacing: .2em; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [data-testid="home-icon"] { + display: grid !important; + width: 54px !important; + height: 50px !important; + place-items: center !important; + border: 3px solid var(--dog-ink) !important; + border-radius: 48% 42% 46% 40% !important; + background: var(--dog-coral) !important; + color: var(--dog-yellow) !important; + box-shadow: 5px 5px 0 var(--dog-ink) !important; + transform: rotate(-4deg) !important; } -.dream-skin-cinematic-actions [data-cinematic-action="replay"] { - padding: 9px 12px; - border-radius: 999px; - color: rgba(199, 229, 224, .56); - font-size: 8px; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [data-testid="home-icon"]::after { + content: "★" !important; + font-size: 27px !important; + line-height: 1 !important; } -#codex-dream-skin-cinematic-ui.is-task .dream-skin-cinematic-transcript, -#codex-dream-skin-cinematic-ui.is-task .dream-skin-cinematic-actions { - display: none; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell [data-testid="home-icon"] > * { + display: none !important; } -html.codex-dream-skin--cinematic-live aside.app-shell-left-panel { - position: relative; - z-index: 5; - border-color: rgba(130, 198, 190, .12) !important; - border-radius: 0 !important; - background: rgba(3, 9, 12, .92) !important; - box-shadow: 12px 0 42px rgba(0, 0, 0, .32) !important; - backdrop-filter: blur(22px) saturate(105%) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell :where(h1, h2) { + width: fit-content !important; + max-width: min(760px, calc(100% - 48px)) !important; + margin-inline: auto !important; + padding: 10px 22px 12px !important; + border: 3px solid var(--dog-ink) !important; + border-radius: 18px 11px 20px 13px !important; + background: + repeating-linear-gradient(2deg, rgba(255,255,255,.16) 0 2px, transparent 2px 8px), + var(--dog-yellow) !important; + color: var(--dog-ink) !important; + box-shadow: 6px 6px 0 var(--dog-ink) !important; + font-family: ui-rounded, "SF Pro Rounded", "PingFang SC", system-ui, sans-serif !important; + font-weight: 950 !important; + letter-spacing: .01em !important; + transform: rotate(-.45deg) !important; } -html.codex-dream-skin--cinematic-live aside.app-shell-left-panel :where(button, a, span, div) { - color: rgba(219, 235, 233, .72) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions { + overflow: visible !important; } -html.codex-dream-skin--cinematic-live aside.app-shell-left-panel svg { - color: rgba(139, 213, 202, .62) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions button { + position: relative !important; + min-height: 112px !important; + padding: 16px 15px !important; + border: 3px solid var(--dog-ink) !important; + border-radius: 15px 10px 18px 12px !important; + background: var(--dog-yellow) !important; + color: var(--dog-ink) !important; + box-shadow: 5px 5px 0 var(--dog-ink) !important; + font-weight: 800 !important; + transform: rotate(-.65deg) !important; + transition: transform .14s ease, box-shadow .14s ease !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface) { - position: relative; - z-index: 1; - border: 0 !important; - border-radius: 0 !important; - background: rgba(1, 6, 9, .05) !important; - box-shadow: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions > * > :nth-child(2) button { + background: #8eddea !important; + transform: rotate(.55deg) !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell { - --color-token-side-bar-background: rgba(3, 12, 16, .7); - --color-token-bg-fog: rgba(3, 12, 16, .78); - --color-token-dropdown-background: rgba(4, 14, 18, .94); - --color-token-list-hover-background: rgba(139, 213, 202, .1); - --color-token-input-background: rgba(3, 12, 16, .7); - --color-token-border: rgba(139, 213, 202, .18); - --color-token-foreground: rgba(236, 248, 246, .94); - --color-token-text-primary: rgba(236, 248, 246, .92); - --color-token-text-secondary: rgba(221, 239, 236, .72); - --color-token-text-tertiary: rgba(205, 228, 224, .56); - --color-text-foreground: rgba(236, 248, 246, .92); +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions > * > :nth-child(3) button { + background: #9ad85d !important; + transform: rotate(-.35deg) !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell - [class*="bg-token-side-bar-background"] { - border: 1px solid rgba(139, 213, 202, .16) !important; - border-bottom: 0 !important; - background: rgba(3, 12, 16, .7) !important; - box-shadow: inset 0 1px rgba(255, 255, 255, .03) !important; - color: rgba(230, 244, 242, .78) !important; - backdrop-filter: blur(22px) saturate(108%) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions > * > :nth-child(4) button { + background: #ff7463 !important; + transform: rotate(.7deg) !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) { - --color-token-bg-fog: rgba(4, 14, 18, .76); - --color-token-dropdown-background: rgba(4, 14, 18, .92); - --color-token-input-background: rgba(4, 14, 18, .82); - --color-token-border: rgba(139, 213, 202, .18); - --color-token-foreground: rgba(236, 248, 246, .94); - --color-background-control: rgba(4, 14, 18, .76); - --color-background-control-opaque: rgb(4, 14, 18); - --color-background-elevated-primary: rgba(4, 14, 18, .92); - --color-background-elevated-primary-opaque: rgb(4, 14, 18); - --color-background-elevated-secondary: rgba(7, 22, 26, .9); - --color-background-elevated-secondary-opaque: rgb(7, 22, 26); - background: rgba(1, 6, 9, .14) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions button:hover { + transform: translate(-2px, -3px) rotate(0deg) !important; + box-shadow: 8px 8px 0 var(--dog-ink) !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface) :is([role="main"], .dream-skin-role-main) { - background: transparent !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions button span:has(> svg) { + display: inline-grid !important; + flex: 0 0 34px !important; + width: 34px !important; + height: 34px !important; + padding: 0 !important; + margin: 0 10px 0 0 !important; + place-items: center !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 50% 44% 48% 42% !important; + background: var(--dog-cream) !important; + color: var(--dog-ink) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell - .group\/home-suggestions { - max-height: 0 !important; - margin: 0 !important; - overflow: hidden !important; - opacity: 0 !important; - pointer-events: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions button svg { + display: block !important; + width: 20px !important; + height: 20px !important; + padding: 0 !important; + border: 0 !important; + border-radius: 0 !important; + background: transparent !important; + color: var(--dog-ink) !important; + box-shadow: none !important; + overflow: visible !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface).dream-skin-home-shell - [data-feature="game-source"] { - opacity: 0 !important; - pointer-events: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .composer-surface-chrome, +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-composer { + max-width: min(760px, calc(100vw - 42px)) !important; + margin-inline: auto !important; + border: 3px solid var(--dog-ink) !important; + background: + repeating-linear-gradient(3deg, rgba(255,216,74,.09) 0 2px, transparent 2px 9px), + var(--dog-cream) !important; + box-shadow: 7px 7px 0 var(--dog-ink) !important; } -html.codex-dream-skin--cinematic-live :is(.composer-surface-chrome, .dream-skin-composer) { - width: min(58vw, 670px) !important; - max-width: calc(100% - 56px) !important; - margin-right: auto !important; - margin-left: clamp(28px, 6vw, 88px) !important; - border: 1px solid rgba(139, 213, 202, .24) !important; - border-radius: 22px !important; - background: rgba(3, 12, 16, .62) !important; - box-shadow: - 0 24px 68px rgba(0, 0, 0, .28), - inset 0 1px rgba(255, 255, 255, .04) !important; - color: rgba(234, 246, 244, .92) !important; - backdrop-filter: blur(24px) saturate(108%) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-composer-stamp { + left: 50% !important; + right: auto !important; + bottom: 124px !important; + width: 78px !important; + padding: 5px !important; + transform: translateX(-50%) rotate(-3deg) !important; } -html.codex-dream-skin--cinematic-live :is(.composer-surface-chrome, .dream-skin-composer)::before { - display: none !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-composer-stamp img { + width: 54px !important; + height: 54px !important; } -html.codex-dream-skin--cinematic-live :is(.composer-surface-chrome, .dream-skin-composer) :where(*, .ProseMirror) { - color: rgba(230, 243, 241, .88) !important; - caret-color: #8be0d2 !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-composer-stamp span { + width: 68px !important; + max-width: 68px !important; + font-size: 8px !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container { - width: min(61%, 780px) !important; - margin-right: auto !important; - margin-left: clamp(18px, 4vw, 58px) !important; - background: transparent !important; - --color-text-foreground: rgba(236, 248, 246, .94); - --color-text-foreground-secondary: rgba(221, 239, 236, .74); - --color-text-foreground-tertiary: rgba(205, 228, 224, .58); - --color-icon-primary: rgba(236, 248, 246, .92); - --color-icon-secondary: rgba(213, 235, 231, .68); - --color-icon-tertiary: rgba(195, 224, 219, .52); - --color-token-conversation-body: rgba(236, 248, 246, .94); - --color-token-text-secondary: rgba(221, 239, 236, .74); - --color-token-text-tertiary: rgba(205, 228, 224, .58); - --color-token-conversation-summary-leading: rgba(230, 244, 242, .84); - --color-token-conversation-summary-trailing: rgba(210, 233, 229, .64); - --color-token-conversation-header: rgba(213, 235, 231, .68); - --color-token-description-foreground: rgba(216, 236, 233, .7); - --shimmer-text-secondary: rgba(216, 236, 233, .7); - --shimmer-contrast: #edf8f6; - color: rgba(236, 248, 246, .94) !important; - text-shadow: none; -} +@media (max-height: 760px), (max-width: 980px) { + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/home-suggestions button { + min-height: 92px !important; + padding: 11px !important; + } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container :where( - .text-token-foreground, - .text-token-conversation-body, - .text-token-conversation-summary-leading, - .text-token-conversation-summary-trailing, - .text-token-description-foreground, - .text-token-text-secondary, - .text-token-text-tertiary, - .group\/activity-header, - .group\/activity-header span, - .group\/activity-header svg - ) { - color: rgba(226, 242, 239, .84) !important; + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-composer-stamp { + display: none !important; + } } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container [class*="_markdownContent_"] { - padding: 13px 15px; - border: 1px solid rgba(139, 213, 202, .16); - border-radius: 14px; - background: rgba(3, 11, 15, .58); - box-shadow: 0 18px 50px rgba(0, 0, 0, .22); - color: rgba(236, 248, 246, .94) !important; - backdrop-filter: blur(20px) saturate(108%); +/* Keep the empty-task headline and suggestion grid on the same responsive + content rail. Viewport-relative offsets can push the first card under the + sidebar, especially when Codex changes the width of its main pane. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell :is( + .dream-skin-happy-home-title, + .group\/home-suggestions +) { + width: min(720px, calc(100% - 48px)) !important; + max-width: min(720px, calc(100% - 48px)) !important; + margin-inline: auto !important; + transform: none !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container [class*="_markdownContent_"] - :where(p, li, h1, h2, h3, h4, h5, h6, strong, em, blockquote, span) { - color: rgba(236, 248, 246, .94) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-fallback-suggestions { + position: absolute !important; + left: 50% !important; + right: auto !important; + display: block !important; + transform: translateX(-50%) !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container [class*="_markdownContent_"] a { - color: #8be0d2 !important; - text-decoration-color: rgba(139, 224, 210, .56) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .dream-skin-happy-fallback-grid { + display: grid !important; + grid-template-columns: repeat(4, minmax(0, 1fr)) !important; + gap: 12px !important; + width: 100% !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - :where(article, .message, [data-message-author-role]) { - border: 1px solid rgba(139, 213, 202, .16) !important; - background: rgba(3, 11, 15, .58) !important; - box-shadow: 0 18px 50px rgba(0, 0, 0, .22) !important; - color: rgba(233, 246, 244, .9) !important; - backdrop-filter: blur(20px) saturate(108%) !important; +/* New-task dog illustration. This pseudo-element exists only while the native + empty-task surface is active, so populated conversations never inherit it. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell::before { + content: "" !important; + position: absolute !important; + z-index: 0 !important; + top: 90px !important; + right: clamp(34px, 7vw, 150px) !important; + width: clamp(290px, 30vw, 470px) !important; + aspect-ratio: 1 / 1 !important; + border: 0 !important; + background: var(--dream-skin-art) center / contain no-repeat !important; + opacity: .24 !important; + filter: saturate(118%) contrast(105%) !important; + transform: rotate(3deg) !important; + pointer-events: none !important; + -webkit-mask-image: radial-gradient(ellipse 64% 62% at 50% 48%, #000 48%, transparent 82%) !important; + mask-image: radial-gradient(ellipse 64% 62% at 50% 48%, #000 48%, transparent 82%) !important; } -html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - [data-message-author-role="user"] { - border-color: rgba(122, 217, 201, .28) !important; - background: rgba(26, 83, 77, .66) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell > * { + position: relative !important; + z-index: 1 !important; } -html.codex-dream-skin--cinematic-live :where(pre, code, table, [data-testid*="code"]) { - border-color: rgba(139, 213, 202, .16) !important; - background: rgba(1, 7, 10, .8) !important; - color: #cfe5e1 !important; +/* Project context strip immediately above the empty-task composer. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell div:has(> .horizontal-scroll-fade-mask .group\/project-selector) { + max-width: min(760px, calc(100vw - 42px)) !important; + margin: 10px auto 0 !important; + padding: 7px 10px !important; + border: 3px solid var(--dog-ink) !important; + border-bottom: 0 !important; + border-radius: 15px 10px 0 0 !important; + background: + repeating-linear-gradient(2deg, rgba(255,255,255,.14) 0 2px, transparent 2px 8px), + #8eddea !important; + box-shadow: 6px 3px 0 var(--dog-ink) !important; +} + +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .group\/project-selector > button { + min-height: 30px !important; + padding: 4px 10px !important; + border: 2px solid var(--dog-ink) !important; + border-radius: 9px 6px 10px 7px !important; + background: var(--dog-yellow) !important; + color: var(--dog-ink) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; + font-weight: 850 !important; +} + +/* Keep the actual empty-task prompt prominent and colorful. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .composer-surface-chrome { + min-height: 104px !important; + border-radius: 5px 11px 19px 13px !important; + background: + linear-gradient(90deg, #ffd84a 0 9px, transparent 9px), + repeating-linear-gradient(3deg, rgba(42,177,197,.09) 0 2px, transparent 2px 9px), + var(--dog-cream) !important; + box-shadow: 7px 7px 0 var(--dog-ink) !important; } -html.codex-dream-skin--cinematic-live :where([role="dialog"], [role="menu"], [role="listbox"], [role="tooltip"]) { - border-color: rgba(139, 213, 202, .22) !important; - background: rgba(4, 13, 17, .96) !important; - color: #e9f6f4 !important; - box-shadow: 0 24px 70px rgba(0, 0, 0, .42) !important; +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .composer-surface-chrome:focus-within { + border-color: var(--dog-ink) !important; + box-shadow: 7px 7px 0 var(--dog-coral) !important; } -@media (max-width: 1100px) { - .dream-skin-cinematic-transcript { - left: 38px; - width: 45%; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .composer-surface-chrome :where(textarea, .ProseMirror, [contenteditable="true"]) { + min-height: 48px !important; + padding-inline: 13px !important; + background: transparent !important; + color: var(--dog-ink) !important; + font-weight: 650 !important; +} - .dream-skin-cinematic-actions { - left: 78px; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .composer-surface-chrome :where(button, [role="button"]) { + min-width: 31px !important; + min-height: 31px !important; + margin-inline: 3px !important; + border: 2px solid var(--dog-ink) !important; + background: var(--dog-yellow) !important; + box-shadow: 2px 2px 0 var(--dog-ink) !important; +} - html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container { - width: 68% !important; - margin-left: 18px !important; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell .composer-surface-chrome :where(button, [role="button"]):nth-last-child(-n+2) { + background: var(--dog-green) !important; } -@media (max-width: 899px) { - .dream-skin-cinematic-video { - display: none !important; - } +/* Move the decorative stamp away from the prompt's center. */ +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-composer-stamp { + left: auto !important; + right: max(24px, calc(50% - 465px)) !important; + bottom: 142px !important; + width: 70px !important; + transform: rotate(4deg) !important; +} - .dream-skin-cinematic-poster { - background-position: 68% center; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-composer-stamp:hover { + transform: translateY(-4px) rotate(1deg) !important; + box-shadow: 7px 7px 0 var(--dog-ink) !important; +} - .dream-skin-cinematic-transcript { - left: 24px; - width: calc(100% - 48px); - max-width: 520px; +@media (max-width: 1180px) { + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] main.dream-skin-home-shell::before { + right: 20px !important; + width: 300px !important; + opacity: .16 !important; } - .dream-skin-cinematic-actions { - left: 48px; + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] #codex-dream-skin-chrome.dream-skin-home-shell .dream-skin-composer-stamp { + display: none !important; } +} - html.codex-dream-skin--cinematic-live :is(.composer-surface-chrome, .dream-skin-composer), - html.codex-dream-skin--cinematic-live :is(main.main-surface, main.dream-skin-main-surface):not(.dream-skin-home-shell) - .thread-scroll-container { - width: calc(100% - 32px) !important; - max-width: none !important; - margin-right: 16px !important; - margin-left: 16px !important; - } +html.codex-dream-skin[data-dream-theme="happy-coding-dog"] :where( + [class*="FileHeader"], + [class*="file-header"], + [data-testid*="file-header"] +) { + padding: 7px 10px !important; + border-block: 2px solid var(--dog-marker-shadow) !important; + background: + linear-gradient(90deg, color-mix(in srgb, var(--dog-marker-green) 32%, #fffaf0), #fffaf0 62%) !important; + color: var(--dog-marker-shadow) !important; + font-weight: 850 !important; } -@media (prefers-reduced-motion: reduce) { - .dream-skin-cinematic-video { - display: none !important; +@media (max-width: 900px) { + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] aside.app-shell-left-panel { + max-width: 210px !important; } - .dream-skin-cinematic-actions button { - transition: none; + html.codex-dream-skin[data-dream-theme="happy-coding-dog"] [data-markdown-text-style="assistant-message"] { + padding-inline: 18px 12px !important; } } diff --git a/assets/inject/renderer-inject.js b/assets/inject/renderer-inject.js index 6d980f3..28cc4d4 100644 --- a/assets/inject/renderer-inject.js +++ b/assets/inject/renderer-inject.js @@ -179,6 +179,120 @@ const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v)); const clamp01 = (v) => clamp(Number(v) || 0, 0, 1); + const HAPPY_DOG_SIDEBAR_ICONS = [ + ["new-chat", /^(?:新对话|new chat)$/i], + ["pull-requests", /^(?:拉取请求|pull requests?)$/i], + ["sites", /^(?:站点|sites?)$/i], + ["scheduled", /^(?:已安排|scheduled)$/i], + ["plugins", /^(?:插件|plugins?)$/i], + ["security", /^(?:安全|security)$/i], + ]; + const HAPPY_DOG_SIDEBAR_ACTIONS = [ + ["search", /(?:^|\s)(?:搜索|search)(?:$|\s)/i], + ["activity", /(?:查看活动|activity|notifications?)/i], + ["quick-chat", /(?:快速聊天|quick chat)/i], + ["profile", /(?:个人资料|profile)/i], + ["voice", /(?:语音|voice)/i], + ["help", /(?:帮助|help)/i], + ]; + const HAPPY_DOG_CHROME_ACTIONS = [ + ["sidebar", /(?:隐藏侧边栏|显示侧边栏|hide sidebar|show sidebar)/i], + ["back", /^(?:返回|back)$/i], + ["forward", /^(?:前进|forward)$/i], + ]; + + const annotateHappyDogSidebar = () => { + if (THEME.id !== "happy-coding-dog") return; + const sidebar = document.querySelector("aside.app-shell-left-panel"); + if (!sidebar) return; + + const interactive = [...sidebar.querySelectorAll("button, a, [role=button]")]; + for (const item of interactive) { + item.removeAttribute("data-dream-dog-icon"); + item.removeAttribute("data-dream-dog-project"); + item.removeAttribute("data-dream-dog-action"); + const text = (item.textContent || "").replace(/\s+/g, " ").trim(); + const label = `${text} ${item.getAttribute("aria-label") || ""} ${item.title || ""}` + .replace(/\s+/g, " ") + .trim(); + const match = HAPPY_DOG_SIDEBAR_ICONS.find(([, pattern]) => pattern.test(text)); + if (match && item.querySelector("svg")) item.setAttribute("data-dream-dog-icon", match[0]); + const action = HAPPY_DOG_SIDEBAR_ACTIONS.find(([, pattern]) => pattern.test(label)); + if (action) item.setAttribute("data-dream-dog-action", action[0]); + if (item.classList.contains("group/folder-row") && item.querySelector("svg")) { + item.setAttribute("data-dream-dog-project", ""); + } + } + + sidebar.querySelectorAll('[class*="_Project"], [class*="_Workspace"]').forEach((node) => { + const item = node.matches("button, a, [role=button]") + ? node + : node.closest("button, a, [role=button]"); + if (item?.querySelector("svg") && !item.hasAttribute("data-dream-dog-icon")) { + item.setAttribute("data-dream-dog-project", ""); + } + }); + + document.querySelectorAll("button, a, [role=button]").forEach((item) => { + item.removeAttribute("data-dream-dog-chrome-action"); + const label = `${item.getAttribute("aria-label") || ""} ${item.title || ""}`.trim(); + const action = HAPPY_DOG_CHROME_ACTIONS.find(([, pattern]) => pattern.test(label)); + if (action && item.querySelector("svg")) { + item.setAttribute("data-dream-dog-chrome-action", action[0]); + } + }); + }; + + const annotateHappyDogResourcePanel = () => { + const selector = "[data-dream-dog-resource-panel], [data-dream-dog-resource-header], [data-dream-dog-resource-add], [data-dream-dog-resource-row], [data-dream-dog-resource-view-all]"; + document.querySelectorAll(selector).forEach((node) => { + for (const name of ["panel", "header", "add", "row", "view-all"]) { + node.removeAttribute(`data-dream-dog-resource-${name}`); + } + }); + if (THEME.id !== "happy-coding-dog") return; + + const sections = [...document.querySelectorAll('section[role="presentation"]')]; + const findSection = (pattern) => sections.find((section) => { + const heading = section.querySelector(":scope > header"); + return heading && pattern.test((heading.textContent || "").replace(/\s+/g, " ").trim()); + }); + const output = findSection(/^(?:输出内容|output)$/i); + const sources = findSection(/^(?:来源|sources?)$/i); + if (!output || !sources) return; + + let common = output.parentElement; + while (common && !common.contains(sources)) common = common.parentElement; + if (!common) return; + const panel = common.closest('[class*="bg-surface-elevated"]') || common; + panel.setAttribute("data-dream-dog-resource-panel", ""); + + for (const [section, kind] of [[output, "output"], [sources, "sources"]]) { + const header = section.querySelector(":scope > header"); + if (!header) continue; + header.setAttribute("data-dream-dog-resource-header", kind); + [...header.querySelectorAll("button")] + .filter((button) => !button.classList.contains("group/section-toggle")) + .forEach((button) => button.setAttribute("data-dream-dog-resource-add", kind)); + } + + const rows = [...output.querySelectorAll('[data-slot="thread-summary-panel-item-button"]'), + ...sources.querySelectorAll('[data-slot="thread-summary-panel-item-button"]')]; + rows.forEach((row) => { + const label = `${row.getAttribute("aria-label") || ""} ${row.textContent || ""}`.trim(); + if (/^(?:查看全部|view all)$/i.test((row.textContent || "").trim())) { + row.setAttribute("data-dream-dog-resource-view-all", ""); + row.setAttribute("data-dream-dog-resource-row", "link"); + } else if (/(?:创建文件或站点|create (?:a )?(?:file|site))/i.test(label)) { + row.setAttribute("data-dream-dog-resource-row", "create"); + } else if (/\.(?:png|jpe?g|gif|webp|svg|avif)\b/i.test(label)) { + row.setAttribute("data-dream-dog-resource-row", "image"); + } else { + row.setAttribute("data-dream-dog-resource-row", "file"); + } + }); + }; + const hexToRgb = (hex) => { const m = /^#([0-9a-f]{6})$/i.exec(hex.trim()); if (!m) return null; @@ -845,6 +959,7 @@ document.querySelectorAll(".dream-skin-home-shell").forEach((node) => node.classList.remove("dream-skin-home-shell")); document.querySelectorAll(".dream-skin-main-surface").forEach((node) => node.classList.remove("dream-skin-main-surface")); document.querySelectorAll(".dream-skin-composer").forEach((node) => node.classList.remove("dream-skin-composer")); + document.querySelectorAll(".dream-skin-composer-dock").forEach((node) => node.classList.remove("dream-skin-composer-dock")); document.querySelectorAll(".dream-skin-role-main").forEach((node) => node.classList.remove("dream-skin-role-main")); document.getElementById(MOONLIT_WELCOME_ID)?.remove(); document.getElementById(BLUE_WINDOW_HOME_ID)?.remove(); @@ -875,6 +990,8 @@ root.classList.add("codex-dream-skin"); root.classList.remove(...LAYOUT_CLASSES); root.classList.add(`codex-dream-skin--${layout}`); + annotateHappyDogSidebar(); + annotateHappyDogResourcePanel(); root.classList.toggle("codex-dream-skin--dark", shell === "dark"); root.classList.toggle("codex-dream-skin--light", shell === "light"); root.setAttribute(SHELL_ATTR, shell); @@ -949,27 +1066,159 @@ cinematicUi?.classList.contains("is-home") && isRenderedElement(cinematicUi); const visibleThemeHome = visibleBlueWindowHome || Boolean(visibleCinematicHome); + const visibleWelcome = [...candidate.querySelectorAll("h1,h2,h3,p")].some((node) => + /我们应该在.+中做些什么|What should we do in/i.test((node.textContent || "").trim()) && + isRenderedElement(node)); return isActiveHomeSurface({ withinShell: candidate === shellMain || Boolean(shellMain?.contains(candidate)), connected: candidate.isConnected, rendered: isRenderedElement(candidate), visibleThemeHome, + visibleWelcome, visibleGameSource: isRenderedElement(candidate.querySelector('[data-feature="game-source"]')), visibleSuggestions: isRenderedElement(candidate.querySelector('.group\\/home-suggestions')), visibleTaskContent, }); }) || null; const layoutHome = PRESERVE_NATIVE_LAYOUT ? null : home; + document.querySelectorAll(".dream-skin-happy-home-title,.dream-skin-happy-home-voice").forEach((node) => { + node.classList.remove("dream-skin-happy-home-title", "dream-skin-happy-home-voice"); + }); + document.querySelectorAll(".dream-skin-native-home-dog").forEach((node) => { + if (!home || node.parentElement !== home) node.remove(); + }); + if (THEME.id === "happy-coding-dog" && home) { + home.classList.add("dream-skin-happy-home-canvas"); + let nativeHomeDog = home.querySelector(":scope > .dream-skin-native-home-dog"); + if (!nativeHomeDog) { + nativeHomeDog = document.createElement("img"); + nativeHomeDog.className = "dream-skin-native-home-dog"; + nativeHomeDog.alt = ""; + home.prepend(nativeHomeDog); + } + if (nativeHomeDog.getAttribute("src") !== artUrl) nativeHomeDog.setAttribute("src", artUrl); + shellMain.querySelectorAll(".group\\/home-suggestions button").forEach((button, index) => { + button.classList.add(`dream-skin-happy-home-card-${index + 1}`); + }); + const visibleHomeNodes = [...shellMain.querySelectorAll("h1,h2,h3,p,div")]; + const welcomeNode = visibleHomeNodes.find((node) => { + const text = (node.textContent || "").trim(); + const rect = node.getBoundingClientRect(); + return node.children.length <= 2 && /我们应该在.+中做些什么|What should we do in/i.test(text) && + rect.width > 180 && rect.height > 20 && rect.height < 130; + }); + const homeTitle = welcomeNode?.closest("h1,h2,h3") || welcomeNode; + homeTitle?.classList.add("dream-skin-happy-home-title"); + + const nativeSuggestions = home.querySelector( + ".group\\/home-suggestions:not(.dream-skin-happy-fallback-suggestions)", + ); + let fallbackSuggestions = home.querySelector(".dream-skin-happy-fallback-suggestions"); + if (!nativeSuggestions && homeTitle && !fallbackSuggestions) { + const suggestionHost = homeTitle.querySelector(':scope > [class*="top-full"]'); + if (suggestionHost) { + fallbackSuggestions = suggestionHost; + fallbackSuggestions.classList.add( + "group/home-suggestions", + "dream-skin-happy-fallback-suggestions", + ); + fallbackSuggestions.innerHTML = ` +
+
+
+
+
+
`; + const prompts = { + understand: "探索并理解这个项目的代码结构", + build: "构建一个新功能、应用或工具", + review: "审查代码并提出修改建议", + fix: "定位并修复项目中的问题和失败", + }; + fallbackSuggestions.querySelectorAll("[data-happy-suggestion]").forEach((button, index) => { + button.classList.add(`dream-skin-happy-home-card-${index + 1}`); + button.addEventListener("click", () => { + const prompt = prompts[button.getAttribute("data-happy-suggestion")] || ""; + const composer = home.querySelector('textarea, [contenteditable="true"]'); + if (!composer || !prompt) return; + if (composer instanceof HTMLTextAreaElement || composer instanceof HTMLInputElement) { + const prototype = composer instanceof HTMLTextAreaElement + ? HTMLTextAreaElement.prototype + : HTMLInputElement.prototype; + const setter = Object.getOwnPropertyDescriptor(prototype, "value")?.set; + if (setter) setter.call(composer, prompt); + else composer.value = prompt; + } else { + composer.textContent = prompt; + } + composer.dispatchEvent(new InputEvent("input", { + bubbles: true, + inputType: "insertText", + data: prompt, + })); + composer.focus(); + }); + }); + } + } else if (nativeSuggestions && fallbackSuggestions) { + fallbackSuggestions.replaceChildren(); + fallbackSuggestions.classList.remove( + "group/home-suggestions", + "dream-skin-happy-fallback-suggestions", + ); + } + + const isHappyVoiceCardCandidate = (node) => { + if (!node) return false; + const rect = node.getBoundingClientRect(); + return rect.width >= 420 && rect.height >= 45 && rect.height <= 110; + }; + const voiceLabel = visibleHomeNodes.find((node) => + node.children.length <= 2 && + /试试 ChatGPT 语音|Try ChatGPT voice/i.test((node.textContent || "").trim()) && + isHappyVoiceCardCandidate(node)); + let voiceCard = voiceLabel; + for (let depth = 0; voiceCard?.parentElement && depth < 5; depth += 1) { + const parent = voiceCard.parentElement; + if (isHappyVoiceCardCandidate(parent)) voiceCard = parent; + else break; + } + if (voiceCard && isHappyVoiceCardCandidate(voiceCard)) { + voiceCard.classList.add("dream-skin-happy-home-voice"); + } + } + document.querySelectorAll(".dream-skin-happy-home-canvas").forEach((node) => { + if (node !== home) node.classList.remove("dream-skin-happy-home-canvas"); + }); if (shellMain) shellMain.classList.add("dream-skin-main-surface"); if (mainContentSurface && mainContentSurface !== shellMain) { mainContentSurface.classList.add("dream-skin-role-main"); } + const composerDock = shellMain?.querySelector('[class*="_ComposerLayoutRoot_"]') || null; + const composerBody = composerDock?.querySelector('[class*="_ComposerLayoutBody_"]') || null; const composerRoot = document.querySelector(".composer-surface-chrome") || - shellMain?.querySelector('[class*="_ComposerLayoutRoot_"]') || - shellMain?.querySelector('.ProseMirror')?.closest('[class*="_Composer"]') || - shellMain?.querySelector('[contenteditable="true"]')?.closest('[class*="_Composer"]'); - if (composerRoot instanceof HTMLElement) composerRoot.classList.add("dream-skin-composer"); + composerBody || + shellMain?.querySelector('.ProseMirror')?.closest('[class*="_Composer"]:not([class*="_ComposerLayoutRoot_"])') || + shellMain?.querySelector('[contenteditable="true"]')?.closest('[class*="_Composer"]:not([class*="_ComposerLayoutRoot_"])') || + composerDock; + if (composerRoot instanceof HTMLElement) { + composerRoot.classList.remove("dream-skin-composer-dock"); + composerRoot.classList.add("dream-skin-composer"); + } + if (composerDock instanceof HTMLElement && composerDock !== composerRoot) { + composerDock.classList.remove("dream-skin-composer"); + composerDock.classList.add("dream-skin-composer-dock"); + } + if (composerRoot instanceof HTMLElement) { + let depth = 0; + for (let node = composerRoot.parentElement; node && node !== shellMain && depth < 3; node = node.parentElement, depth += 1) { + node.classList.add("dream-skin-composer-dock"); + } + } + if (composerDock instanceof HTMLElement && composerDock !== composerRoot) { + composerDock.classList.remove("dream-skin-composer"); + } for (const candidate of document.querySelectorAll('[role="main"].dream-skin-home, .dream-skin-role-main.dream-skin-home')) { if (candidate !== layoutHome) candidate.classList.remove("dream-skin-home"); @@ -987,6 +1236,7 @@ let chrome = document.getElementById(CHROME_ID); const chromeIsCurrent = Boolean( chrome?.querySelector(".dream-skin-composer-stamp img") && + chrome?.querySelector(".dream-skin-home-dog-backdrop") && chrome?.querySelector(".dream-skin-retro-mascot") && chrome?.querySelector(".dream-skin-retro-friend-avatar") && chrome?.querySelector(".dream-skin-retro-friend-search") && @@ -998,6 +1248,7 @@ chrome.id = CHROME_ID; chrome.setAttribute("aria-hidden", "true"); chrome.innerHTML = ` +
✦ @@ -1116,7 +1367,67 @@ /[A-Za-z][A-Za-z' ]+/.exec(themeName)?.[0].trim() || themeName; const stampImg = chrome.querySelector(".dream-skin-composer-stamp img"); if (stampImg.getAttribute("src") !== stampUrl) stampImg.setAttribute("src", stampUrl); - chrome.querySelector(".dream-skin-composer-stamp span").textContent = copy.quote || "MAKE SOMETHING WONDERFUL"; + const homeDogBackdrop = chrome.querySelector(".dream-skin-home-dog-backdrop"); + if (homeDogBackdrop.getAttribute("src") !== artUrl) homeDogBackdrop.setAttribute("src", artUrl); + const stampLabel = chrome.querySelector(".dream-skin-composer-stamp span"); + const stampCopy = copy.quote || "MAKE SOMETHING WONDERFUL"; + if (THEME.id === "happy-coding-dog" && stampCopy.includes(",")) { + const splitAt = stampCopy.indexOf(",") + 1; + stampLabel.replaceChildren( + document.createTextNode(stampCopy.slice(0, splitAt)), + document.createElement("br"), + document.createTextNode(stampCopy.slice(splitAt)), + ); + } else { + stampLabel.textContent = stampCopy; + } + if (THEME.id === "happy-coding-dog") { + const reviewClasses = [ + "dream-skin-review-toolbar", + "dream-skin-review-tab", + "dream-skin-review-close", + "dream-skin-review-add", + "dream-skin-review-action", + ]; + document.querySelectorAll(reviewClasses.map((name) => `.${name}`).join(",")).forEach((node) => { + reviewClasses.forEach((name) => node.classList.remove(name)); + }); + + const reviewLabel = [...document.querySelectorAll("button,[role=\"tab\"],[role=\"button\"],span,div")].find((node) => { + const rect = node.getBoundingClientRect(); + return node.children.length <= 3 && /^(审查|Review)$/i.test((node.textContent || "").trim()) && + rect.width > 0 && rect.width < 320 && rect.height > 0 && rect.top < 84; + }); + const reviewTab = reviewLabel?.closest("button,[role=\"tab\"],[role=\"button\"]") || reviewLabel?.parentElement; + let reviewToolbar = null; + if (reviewTab) { + reviewTab.classList.add("dream-skin-review-tab"); + let candidate = reviewTab.parentElement; + for (let depth = 0; candidate && depth < 8; depth += 1, candidate = candidate.parentElement) { + const rect = candidate.getBoundingClientRect(); + if (rect.top < 66 && rect.width > 280 && rect.height >= 34 && rect.height <= 82) reviewToolbar = candidate; + } + } + if (reviewToolbar) { + reviewToolbar.classList.add("dream-skin-review-toolbar"); + reviewToolbar.querySelectorAll("button,[role=\"button\"]").forEach((button) => { + if (button === reviewTab) return; + const label = `${button.getAttribute("aria-label") || ""} ${button.title || ""} ${button.textContent || ""}`.trim(); + if (/关闭|close|dismiss|^[×x]$/i.test(label)) button.classList.add("dream-skin-review-close"); + else if (/新建|add|new|^\+$/i.test(label)) button.classList.add("dream-skin-review-add"); + else button.classList.add("dream-skin-review-action"); + }); + root.dataset.dreamReviewOpen = "true"; + } else { + delete root.dataset.dreamReviewOpen; + } + + const threadPane = document.querySelector("[data-pip-anchor-host=\"codex-main-thread\"]") || + document.querySelector(".thread-scroll-container")?.parentElement; + const threadWidth = threadPane?.getBoundingClientRect().width || 0; + if (threadWidth > 0 && threadWidth < 580) root.dataset.dreamThreadNarrow = "true"; + else delete root.dataset.dreamThreadNarrow; + } chrome.querySelector(".dream-skin-silk-heading small").textContent = copy.brandSubtitle || "MIRROR LAKE RIBBON"; chrome.querySelector(".dream-skin-silk-heading span").textContent = THEME.tagline || "一卷湖光,写尽风华。"; chrome.querySelector(".dream-skin-silk-status span").textContent = copy.statusText || "湖光正明"; @@ -1133,6 +1444,13 @@ const retroFriendAvatar = chrome.querySelector(".dream-skin-retro-friend-avatar"); if (retroFriendAvatar.getAttribute("src") !== stampUrl) retroFriendAvatar.setAttribute("src", stampUrl); const shellBox = shellMain.getBoundingClientRect(); + if (THEME.id === "happy-coding-dog" && homeDogBackdrop) { + const workspaceBox = (mainContentSurface || shellMain).getBoundingClientRect(); + homeDogBackdrop.style.left = `${Math.max(0, Math.round(workspaceBox.left - shellBox.left))}px`; + homeDogBackdrop.style.top = `${Math.max(59, Math.round(workspaceBox.top - shellBox.top + 59))}px`; + homeDogBackdrop.style.width = `${Math.round(workspaceBox.width)}px`; + homeDogBackdrop.style.height = `${Math.max(240, Math.round(shellBox.bottom - Math.max(workspaceBox.top + 59, shellBox.top + 59)))}px`; + } chrome.style.left = `${Math.round(shellBox.left)}px`; chrome.style.top = `${Math.round(shellBox.top)}px`; chrome.style.width = `${Math.round(shellBox.width)}px`; @@ -1170,22 +1488,49 @@ }; const scheduler = { timeout: null }; + const observerOptions = { + childList: true, + subtree: true, + attributes: true, + characterData: true, + attributeFilter: ["class", "data-theme", "data-appearance", "data-color-mode"], + }; + const THEME_STRUCTURE_SELECTOR = "main, aside.app-shell-left-panel, [class*=_MainContent], [class*=_ComposerLayout], [data-message-author-role], [data-testid=home-icon]"; + const mutationTouchesThemeStructure = (mutation) => + [...mutation.addedNodes, ...mutation.removedNodes].some((node) => + node.nodeType === Node.ELEMENT_NODE && + (node.matches?.(THEME_STRUCTURE_SELECTOR) || node.querySelector?.(THEME_STRUCTURE_SELECTOR)), + ); + const shouldScheduleEnsure = (mutations) => mutations.some((mutation) => { + if (mutation.type === "characterData") return false; + if (mutation.type === "childList") return mutationTouchesThemeStructure(mutation); + if (mutation.type !== "attributes") return false; + if (mutation.attributeName !== "class") return true; + return mutation.target === document.documentElement || + mutation.target === document.body || + mutation.target.matches?.("main, aside.app-shell-left-panel"); + }); + let observer = null; + const runEnsure = () => { + observer.disconnect(); + try { + ensure(); + } finally { + observer.observe(document.documentElement, observerOptions); + } + }; const scheduleEnsure = () => { if (scheduler.timeout) clearTimeout(scheduler.timeout); scheduler.timeout = setTimeout(() => { scheduler.timeout = null; - ensure(); + runEnsure(); }, 180); }; - const observer = new MutationObserver(scheduleEnsure); - observer.observe(document.documentElement, { - childList: true, - subtree: true, - attributes: true, - characterData: true, - attributeFilter: ["class", "aria-label", "data-theme", "data-appearance", "data-color-mode", "style"], + observer = new MutationObserver((mutations) => { + if (shouldScheduleEnsure(mutations)) scheduleEnsure(); }); - const timer = setInterval(ensure, 4000); + observer.observe(document.documentElement, observerOptions); + const timer = setInterval(runEnsure, 4000); const resizeHandler = scheduleEnsure; window.addEventListener("resize", resizeHandler, { passive: true }); @@ -1236,6 +1581,6 @@ detectProductMode, productMode: detectProductMode(), }; - ensure(); + runEnsure(); return { installed: true, version: VERSION, themeId: THEME.id || "custom", shell: detectShellMode() }; })(__DREAM_SKIN_CSS_JSON__, __DREAM_SKIN_ART_JSON__, __DREAM_SKIN_WALLPAPER_JSON__, __DREAM_SKIN_STAMP_JSON__, __DREAM_SKIN_MOTION_JSON__, __DREAM_SKIN_MOTION_POSTER_JSON__, __DREAM_SKIN_THEME_JSON__, __DREAM_SKIN_VARS_JSON__, __DREAM_SKIN_VERSION_JSON__) diff --git a/assets/presets/happy-coding-dog/hero-workspace-blended.png b/assets/presets/happy-coding-dog/hero-workspace-blended.png new file mode 100644 index 0000000..0f0cd07 Binary files /dev/null and b/assets/presets/happy-coding-dog/hero-workspace-blended.png differ diff --git a/assets/presets/happy-coding-dog/hero-workspace-expanded-2400x1600.png b/assets/presets/happy-coding-dog/hero-workspace-expanded-2400x1600.png new file mode 100644 index 0000000..746c7d2 Binary files /dev/null and b/assets/presets/happy-coding-dog/hero-workspace-expanded-2400x1600.png differ diff --git a/assets/presets/happy-coding-dog/hero-workspace-safe.png b/assets/presets/happy-coding-dog/hero-workspace-safe.png new file mode 100644 index 0000000..cc0d051 Binary files /dev/null and b/assets/presets/happy-coding-dog/hero-workspace-safe.png differ diff --git a/assets/presets/happy-coding-dog/hero-workspace-team.png b/assets/presets/happy-coding-dog/hero-workspace-team.png new file mode 100644 index 0000000..acc6e80 Binary files /dev/null and b/assets/presets/happy-coding-dog/hero-workspace-team.png differ diff --git a/assets/presets/happy-coding-dog/hero-workspace.png b/assets/presets/happy-coding-dog/hero-workspace.png new file mode 100644 index 0000000..ad3d551 Binary files /dev/null and b/assets/presets/happy-coding-dog/hero-workspace.png differ diff --git a/assets/presets/happy-coding-dog/hero.png b/assets/presets/happy-coding-dog/hero.png new file mode 100644 index 0000000..6c04b86 Binary files /dev/null and b/assets/presets/happy-coding-dog/hero.png differ diff --git a/assets/presets/happy-coding-dog/preview.png b/assets/presets/happy-coding-dog/preview.png new file mode 100644 index 0000000..5878344 Binary files /dev/null and b/assets/presets/happy-coding-dog/preview.png differ diff --git a/assets/presets/happy-coding-dog/stamp.png b/assets/presets/happy-coding-dog/stamp.png new file mode 100644 index 0000000..0a86128 Binary files /dev/null and b/assets/presets/happy-coding-dog/stamp.png differ diff --git a/assets/presets/happy-coding-dog/theme.json b/assets/presets/happy-coding-dog/theme.json new file mode 100644 index 0000000..515c139 --- /dev/null +++ b/assets/presets/happy-coding-dog/theme.json @@ -0,0 +1,78 @@ +{ + "schemaVersion": 2, + "uuid": "preset-happy-coding-dog", + "id": "happy-coding-dog", + "version": "1.1.0", + "minEngineVersion": "2.0.0", + "name": "快乐码犬 Happy Coding Dog", + "description": "粗线条、亮色块与马克笔笔触组成的快乐狗狗手绘工作台。", + "tagline": "新的一天开始啦,今天要做什么?", + "tags": [ + "狗狗", + "手绘", + "治愈", + "高饱和" + ], + "hero": "hero-workspace-blended.png", + "preview": "preview.png", + "wallpaper": "wallpaper.png", + "stamp": "stamp.png", + "light": { + "background": "#fff5d8", + "panel": "#fffaf0", + "panelAlt": "#f4efd9", + "surface": "#ffffff", + "text": "#20201d", + "muted": "#776f62", + "border": "rgba(32, 32, 29, 0.24)", + "accent": "#087f98", + "accentAlt": "#23b7c9", + "secondary": "#f04f3d", + "highlight": "#f2be16" + }, + "dark": { + "background": "#171b1c", + "panel": "#202627", + "panelAlt": "#293031", + "surface": "#242a2b", + "text": "#fff5d8", + "muted": "#bbb4a6", + "border": "rgba(255, 245, 216, 0.19)", + "accent": "#38c5d3", + "accentAlt": "#77d9df", + "secondary": "#ff7261", + "highlight": "#ffd84a" + }, + "layout": "dream-banner", + "heroFit": "cover", + "heroFocusX": 0.62, + "heroFocusY": 0.5, + "heroZoom": 1, + "heroHeight": 360, + "heroTextAlign": "left", + "heroScrim": 0.16, + "wallpaperEnabled": true, + "wallpaperFocusX": 0.5, + "wallpaperFocusY": 0.5, + "wallpaperOpacity": 0.45, + "wallpaperBlur": 0, + "radius": "xl", + "density": "spacious", + "fontPreset": "rounded", + "glass": false, + "shadow": "lg", + "decoration": 0.86, + "effects": { + "particles": 0.16, + "aurora": 0, + "glow": 0.06, + "noise": 0.08, + "grid": 0, + "float": 0.12 + }, + "brandSubtitle": "HAPPY CODING", + "projectPrefix": "快乐任务 · ", + "projectLabel": "选择今天的任务", + "statusText": "TAIL WAGGING · ONLINE", + "quote": "人生是旷野,没矿不敢野" +} \ No newline at end of file diff --git a/assets/presets/happy-coding-dog/wallpaper.png b/assets/presets/happy-coding-dog/wallpaper.png new file mode 100644 index 0000000..746c7d2 Binary files /dev/null and b/assets/presets/happy-coding-dog/wallpaper.png differ diff --git a/assets/presets/yan-companion/motion-poster.webp b/assets/presets/yan-companion/motion-poster.webp new file mode 100644 index 0000000..28de698 Binary files /dev/null and b/assets/presets/yan-companion/motion-poster.webp differ diff --git a/assets/presets/yan-companion/motion.mp4 b/assets/presets/yan-companion/motion.mp4 new file mode 100644 index 0000000..0bd5e13 Binary files /dev/null and b/assets/presets/yan-companion/motion.mp4 differ diff --git a/assets/presets/yan-companion/preview.png b/assets/presets/yan-companion/preview.png new file mode 100644 index 0000000..6faf083 Binary files /dev/null and b/assets/presets/yan-companion/preview.png differ diff --git a/assets/presets/yan-companion/theme.json b/assets/presets/yan-companion/theme.json new file mode 100644 index 0000000..76ba8aa --- /dev/null +++ b/assets/presets/yan-companion/theme.json @@ -0,0 +1,79 @@ +{ + "schemaVersion": 2, + "uuid": "preset-yan-companion", + "id": "yan-companion", + "version": "1.0.0", + "minEngineVersion": "1.1.0", + "galleryVisible": true, + "name": "沉浸伴生 Yan Companion", + "description": "右侧动态人物、深夜电影光效与左侧玻璃对话层组成的沉浸式 Codex 工作台。", + "tagline": "让她陪你把想法写成结果。", + "tags": [ + "动态", + "陪伴", + "电影感", + "沉浸" + ], + "hero": "motion-poster.webp", + "preview": "preview.png", + "motionBackground": "motion.mp4", + "motionPoster": "motion-poster.webp", + "light": { + "background": "#03070a", + "panel": "#071014", + "panelAlt": "#0a171b", + "surface": "#071014", + "text": "#edf8f6", + "muted": "#94aaa7", + "border": "rgba(139, 213, 202, 0.2)", + "accent": "#65bfae", + "accentAlt": "#8be0d2", + "secondary": "#bf8f78", + "highlight": "#4c8d86" + }, + "dark": { + "background": "#020608", + "panel": "#061014", + "panelAlt": "#09171b", + "surface": "#071216", + "text": "#edf8f6", + "muted": "#94aaa7", + "border": "rgba(139, 213, 202, 0.2)", + "accent": "#65bfae", + "accentAlt": "#8be0d2", + "secondary": "#bf8f78", + "highlight": "#4c8d86" + }, + "layout": "cinematic-live", + "heroFit": "cover", + "heroFocusX": 0.72, + "heroFocusY": 0.5, + "heroZoom": 1, + "heroHeight": 340, + "heroTextAlign": "left", + "heroScrim": 0.24, + "wallpaperEnabled": false, + "wallpaperFocusX": 0.5, + "wallpaperFocusY": 0.5, + "wallpaperOpacity": 0, + "wallpaperBlur": 0, + "radius": "md", + "density": "normal", + "fontPreset": "system", + "glass": true, + "shadow": "lg", + "decoration": 0.3, + "effects": { + "particles": 0, + "aurora": 0, + "glow": 0.18, + "noise": 0.08, + "grid": 0, + "float": 0 + }, + "brandSubtitle": "YAN COMPANION", + "projectPrefix": "当前项目 · ", + "projectLabel": "选择工作项目", + "statusText": "OBJECT LIVE · 伴生在线", + "quote": "把想法告诉我,我们一起推进" +} diff --git a/electron/controller.test.ts b/electron/controller.test.ts new file mode 100644 index 0000000..4d9d3e7 --- /dev/null +++ b/electron/controller.test.ts @@ -0,0 +1,14 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { canAttemptAutoApply, shouldStopStaleWatcher } from "./controller"; + +test("a running watcher cannot block auto-apply after its CDP endpoint disappears", () => { + assert.equal(shouldStopStaleWatcher(true, false), true); + assert.equal(shouldStopStaleWatcher(true, true), false); + assert.equal(shouldStopStaleWatcher(false, false), false); +}); + +test("auto-apply cannot restart Codex again before the user ends the current run", () => { + assert.equal(canAttemptAutoApply(false), true); + assert.equal(canAttemptAutoApply(true), false); +}); diff --git a/electron/controller.ts b/electron/controller.ts index bf058d4..52f84ac 100644 --- a/electron/controller.ts +++ b/electron/controller.ts @@ -15,7 +15,7 @@ import { EventEmitter } from "node:events"; import fs from "node:fs/promises"; -import type { AppState, ApplyResult, ApplyStatus, CodexCliStatus, LayoutKind, LogLine } from "./shared/types"; +import type { AppState, ApplyResult, ApplyStatus, ApplyThemeOptions, CodexCliStatus, LayoutKind, LogLine, ThemeSource } from "./shared/types"; import type { AppPaths } from "./paths"; import { PREFERRED_CDP_PORT, SKIN_VERSION } from "./engine/constants"; import { buildPayload } from "./engine/payload"; @@ -48,6 +48,7 @@ import type { interface PersistedState { activeThemeId: string | null; activeThemeName: string | null; + activeThemeSource: ThemeSource | null; activeLayout: LayoutKind | null; cdpPort: number | null; appliedAt: string | null; @@ -61,11 +62,25 @@ const AUTO_APPLY_SETTLE_MS = 4_000; const EMPTY_PERSISTED: PersistedState = { activeThemeId: null, activeThemeName: null, + activeThemeSource: null, activeLayout: null, cdpPort: null, appliedAt: null, }; +function isThemeSource(value: unknown): value is ThemeSource { + return value === "preset" || value === "custom" || value === "imported" || value === "purchased"; +} + +export function shouldStopStaleWatcher(watcherActive: boolean, cdpHealthy: boolean): boolean { + return watcherActive && !cdpHealthy; +} + +/** Allow at most one automatic restart during one observed Codex run. */ +export function canAttemptAutoApply(restartBlocked: boolean): boolean { + return !restartBlocked; +} + /** * Keep local filesystem paths and Codex thread/turn identifiers in the main * process. Renderer consumers only need stable UI ids and preview URLs. @@ -108,6 +123,7 @@ export class ThemeController extends EventEmitter { private codexRunning = false; private cdpHealthy = false; private autoApplyRunningSince: number | null = null; + private autoApplyRestartBlocked = false; private lastAutoApplyAt = 0; private cliService: CodexCliStatusService; private jobService: AiThemeJobService; @@ -149,6 +165,7 @@ export class ThemeController extends EventEmitter { try { const dir = await this.store.resolveThemeDir(activeThemeId, { preferPurchased: true, + preferredSource: this.persisted.activeThemeSource ?? undefined, allowCatalogOnly: false, }); if (!dir) throw new Error("theme directory is gone"); @@ -275,12 +292,25 @@ export class ThemeController extends EventEmitter { */ async tick(): Promise { await this.refreshStatus(); + if (!this.applying && !this.codexRunning) { + // A real user-driven quit ends the current run. The next launch may make + // one fresh recovery attempt, but a failed recovery cannot loop forever. + this.autoApplyRestartBlocked = false; + } + if (shouldStopStaleWatcher(this.watcher?.active ?? false, this.cdpHealthy)) { + this.log("warn", "Codex 调试端口已失效,正在停止旧注入守护并准备恢复主题。"); + await this.watcher?.stop(); + this.watcher = null; + this.emitState(); + } if (!this.settings?.current.autoApply) { this.autoApplyRunningSince = null; + this.autoApplyRestartBlocked = false; return; } const { activeThemeId } = this.persisted; if (!activeThemeId || this.applying || this.watcher?.active) return; + if (!canAttemptAutoApply(this.autoApplyRestartBlocked)) return; if (!this.install || !this.codexRunning || this.cdpHealthy) { this.autoApplyRunningSince = null; return; @@ -297,9 +327,15 @@ export class ThemeController extends EventEmitter { this.lastAutoApplyAt = Date.now(); this.autoApplyRunningSince = null; this.log("info", "检测到 Codex 未带调试端口启动,按偏好设置自动恢复主题…"); - const result = await this.applyTheme(activeThemeId, { confirmRestart: true }); + const result = await this.applyTheme(activeThemeId, { + confirmRestart: true, + source: this.persisted.activeThemeSource ?? undefined, + }); + // Whether the launch failed outright or CDP disappeared again shortly + // afterwards, do not restart this same observed Codex run a second time. + this.autoApplyRestartBlocked = true; if (!result.ok) { - this.log("warn", `自动应用失败(将在冷却期后重试):${result.error ?? "未知错误"}`); + this.log("warn", `自动应用失败(本次 Codex 运行不再自动重试):${result.error ?? "未知错误"}`); } } @@ -337,7 +373,7 @@ export class ThemeController extends EventEmitter { // ----------------------------------------------------------------- apply - async applyTheme(themeId: string, opts: { confirmRestart?: boolean } = {}): Promise { + async applyTheme(themeId: string, opts: ApplyThemeOptions = {}): Promise { if (this.applying) { return this.result("failed", false, false, [], "另一个主题正在应用中,请稍候。"); } @@ -360,6 +396,7 @@ export class ThemeController extends EventEmitter { } const dir = await this.store.resolveThemeDir(themeId, { preferPurchased: true, + preferredSource: opts.source, allowCatalogOnly: false, }); if (!dir) { @@ -433,6 +470,7 @@ export class ThemeController extends EventEmitter { // 4) Persist, then soft-verify against a live session. this.persisted.activeThemeId = themeId; this.persisted.activeThemeName = themeName; + this.persisted.activeThemeSource = opts.source ?? null; this.persisted.activeLayout = themeLayout; this.persisted.appliedAt = new Date().toISOString(); await this.writePersisted(); @@ -489,6 +527,7 @@ export class ThemeController extends EventEmitter { await restoreAppearanceKeys(this.paths.codexConfigPath, this.paths.configBackupFile); this.persisted.activeThemeId = null; this.persisted.activeThemeName = null; + this.persisted.activeThemeSource = null; this.persisted.activeLayout = null; this.persisted.appliedAt = null; await this.writePersisted(); @@ -556,6 +595,7 @@ export class ThemeController extends EventEmitter { return { activeThemeId: typeof raw?.activeThemeId === "string" ? raw.activeThemeId : null, activeThemeName: typeof raw?.activeThemeName === "string" ? raw.activeThemeName : null, + activeThemeSource: isThemeSource(raw?.activeThemeSource) ? raw.activeThemeSource : null, activeLayout: typeof raw?.activeLayout === "string" ? raw.activeLayout : null, cdpPort: Number.isInteger(raw?.cdpPort) ? raw.cdpPort : null, appliedAt: typeof raw?.appliedAt === "string" ? raw.appliedAt : null, diff --git a/electron/engine/constants.ts b/electron/engine/constants.ts index d5f219b..3ee7b51 100644 --- a/electron/engine/constants.ts +++ b/electron/engine/constants.ts @@ -4,7 +4,7 @@ */ /** Bumped whenever the injected payload format changes. */ -export const SKIN_VERSION = "1.2.0"; +export const SKIN_VERSION = "1.2.4"; export const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "[::1]"]); diff --git a/electron/engine/home-detection.ts b/electron/engine/home-detection.ts index dd073cd..5512080 100644 --- a/electron/engine/home-detection.ts +++ b/electron/engine/home-detection.ts @@ -9,6 +9,7 @@ export interface HomeSurfaceSignals { connected: boolean; rendered: boolean; visibleThemeHome?: boolean; + visibleWelcome?: boolean; visibleGameSource: boolean; visibleSuggestions: boolean; visibleTaskContent: boolean; @@ -20,6 +21,7 @@ export function isActiveHomeSurface(signals: HomeSurfaceSignals): boolean { signals.rendered && !signals.visibleTaskContent && (signals.visibleThemeHome === true || + signals.visibleWelcome === true || signals.visibleGameSource || signals.visibleSuggestions); } diff --git a/electron/engine/package-safety.test.ts b/electron/engine/package-safety.test.ts index 2247b20..5d452b9 100644 --- a/electron/engine/package-safety.test.ts +++ b/electron/engine/package-safety.test.ts @@ -216,6 +216,45 @@ describe("ThemeStore package inspection", () => { assert.equal(resolved, purchasedDir); }); + it("honors the selected library source when duplicate theme ids exist", async () => { + const presetDir = path.join(root, "presets", "source-collision"); + const purchasedDir = path.join(purchasedRoot, "source-collision"); + const baseManifest = JSON.parse(themeJson) as Record; + await Promise.all([ + fs.mkdir(presetDir, { recursive: true }), + fs.mkdir(purchasedDir, { recursive: true }), + ]); + await Promise.all([ + fs.writeFile(path.join(presetDir, "theme.json"), JSON.stringify({ + ...baseManifest, + uuid: "550e8400-e29b-41d4-a716-446655440011", + id: "source-collision", + name: "Preset Theme", + })), + fs.writeFile(path.join(presetDir, "hero.png"), heroPng), + fs.writeFile(path.join(purchasedDir, "theme.json"), JSON.stringify({ + ...baseManifest, + uuid: "550e8400-e29b-41d4-a716-446655440012", + id: "source-collision", + name: "Purchased Theme", + })), + fs.writeFile(path.join(purchasedDir, "hero.png"), heroPng), + ]); + + const preset = await store.resolveThemeDir("source-collision", { + preferPurchased: true, + preferredSource: "preset", + allowCatalogOnly: false, + }); + const purchased = await store.resolveThemeDir("source-collision", { + preferPurchased: true, + preferredSource: "purchased", + allowCatalogOnly: false, + }); + assert.equal(preset, presetDir); + assert.equal(purchased, purchasedDir); + }); + it("never resolves a catalog-only placeholder as an applicable theme", async () => { const placeholderDir = path.join(root, "presets", "preview-only"); const baseManifest = JSON.parse(themeJson) as Record; diff --git a/electron/engine/theme.test.ts b/electron/engine/theme.test.ts index 444f13d..66b7e98 100644 --- a/electron/engine/theme.test.ts +++ b/electron/engine/theme.test.ts @@ -6,6 +6,8 @@ import { describe, it } from "node:test"; import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; import { normalizeTheme, contrastRatio, validateContrast, deriveDarkPalette } from "./normalize"; import { compileTheme } from "./compiler"; import { buildPayload, loadTheme } from "./payload"; @@ -272,6 +274,18 @@ describe("isActiveHomeSurface", () => { ); }); + it("accepts the current new-conversation surface when only its welcome prompt is visible", () => { + assert.equal( + isActiveHomeSurface({ + ...activeHome, + visibleGameSource: false, + visibleSuggestions: false, + visibleWelcome: true, + }), + true, + ); + }); + it("keeps a visible theme-owned home active while native home content is hidden", () => { assert.equal( isActiveHomeSurface({ @@ -415,21 +429,431 @@ describe("loadTheme", () => { } }); - it("embeds the Nightbound Companion video and fallback poster", async () => { + it("embeds cinematic-live video backgrounds and fallback posters", async () => { + for (const id of ["nightbound-companion", "yan-companion"]) { + const built = await buildPayload( + "./assets/inject", + `./assets/presets/${id}`, + ); + assert.equal(built.theme.id, id); + assert.equal(built.theme.layout, "cinematic-live"); + assert.equal(built.theme.resources.motionBackground, "motion.mp4"); + assert.equal(built.theme.resources.motionPoster, "motion-poster.webp"); + assert.ok(built.payload.includes("data:video/mp4;base64,")); + assert.ok(built.payload.includes("dream-skin-cinematic-video")); + assert.ok(built.payload.includes("visibleCinematicHome")); + assert.ok(built.payload.includes(".thread-scroll-container")); + assert.ok(built.payload.includes("prefers-reduced-motion: reduce")); + assert.ok(!built.payload.includes("__DREAM_SKIN_MOTION_JSON__")); + assert.ok(!built.payload.includes("__DREAM_SKIN_MOTION_POSTER_JSON__")); + assert.doesNotThrow(() => new Function(built.payload)); + } + }); +}); + +describe("Happy Coding Dog injected skin", () => { + it("pauses the mutation observer while refreshing the injected theme", async () => { const built = await buildPayload( "./assets/inject", - "./assets/presets/nightbound-companion", - ); - assert.equal(built.theme.layout, "cinematic-live"); - assert.equal(built.theme.resources.motionBackground, "motion.mp4"); - assert.equal(built.theme.resources.motionPoster, "motion-poster.webp"); - assert.ok(built.payload.includes("data:video/mp4;base64,")); - assert.ok(built.payload.includes("dream-skin-cinematic-video")); - assert.ok(built.payload.includes("visibleCinematicHome")); - assert.ok(built.payload.includes(".thread-scroll-container")); - assert.ok(built.payload.includes("prefers-reduced-motion: reduce")); - assert.ok(!built.payload.includes("__DREAM_SKIN_MOTION_JSON__")); - assert.ok(!built.payload.includes("__DREAM_SKIN_MOTION_POSTER_JSON__")); - assert.doesNotThrow(() => new Function(built.payload)); + "./assets/presets/happy-coding-dog", + ); + + assert.match( + built.payload, + /const runEnsure = \(\) => \{[\s\S]*observer\.disconnect\(\)[\s\S]*ensure\(\)[\s\S]*observer\.observe\(document\.documentElement, observerOptions\)/, + "theme-owned class and style mutations must not schedule another refresh", + ); + assert.match(built.payload, /setInterval\(runEnsure, 4000\)/); + assert.match(built.payload, /\n runEnsure\(\);\n return \{ installed:/); + }); + + it("ignores cosmetic attribute churn when deciding whether to refresh the theme", async () => { + const built = await buildPayload( + "./assets/inject", + "./assets/presets/happy-coding-dog", + ); + + assert.match( + built.payload, + /const shouldScheduleEnsure = \(mutations\) => mutations\.some\([\s\S]*mutation\.target === document\.documentElement[\s\S]*mutation\.target === document\.body/, + ); + assert.match( + built.payload, + /new MutationObserver\(\(mutations\) => \{[\s\S]*shouldScheduleEnsure\(mutations\)[\s\S]*scheduleEnsure\(\)/, + ); + assert.doesNotMatch( + built.payload, + /attributeFilter: \[[^\]]*(?:"aria-label"|"style")/, + "tooltip animation and accessibility-label churn must not refresh the whole skin", + ); + }); + + it("ignores timer text and transient portal nodes outside the themed shell", async () => { + const built = await buildPayload( + "./assets/inject", + "./assets/presets/happy-coding-dog", + ); + + assert.match( + built.payload, + /if \(mutation\.type === "characterData"\) return false;/, + ); + assert.match( + built.payload, + /if \(mutation\.type === "childList"\) return mutationTouchesThemeStructure\(mutation\);/, + ); + assert.match( + built.payload, + /const THEME_STRUCTURE_SELECTOR = "main, aside\.app-shell-left-panel,[^"]+_ComposerLayout/, + ); + }); + + it("turns native sidebar navigation glyphs into color-coded hand-drawn stickers", async () => { + const built = await buildPayload( + "./assets/inject", + "./assets/presets/happy-coding-dog", + ); + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + for (const kind of ["new-chat", "pull-requests", "sites", "scheduled", "plugins", "security"]) { + assert.ok( + built.payload.includes(`["${kind}",`), + `the injected sidebar annotator must classify ${kind}`, + ); + assert.ok( + css.includes(`[data-dream-dog-icon="${kind}"]`), + `missing Happy Coding Dog sticker treatment for ${kind}`, + ); + } + assert.match( + css, + /data-dream-dog-icon[^{}]*svg[^{}]*\{[^}]*stroke-width:\s*2\.35[^}]*filter:\s*drop-shadow/s, + "sidebar glyphs should use a heavier hand-drawn line and offset ink shadow", + ); + assert.match( + css, + /data-dream-dog-project[^{}]*svg[^{}]*\{[^}]*background:\s*var\(--dog-yellow\)/s, + "project folders should share the cream-yellow sticker language", + ); + }); + + it("styles the sidebar utility actions and keeps icon labels comfortably spaced", async () => { + const built = await buildPayload( + "./assets/inject", + "./assets/presets/happy-coding-dog", + ); + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + for (const kind of ["search", "activity", "quick-chat", "profile", "voice", "help"]) { + assert.ok(built.payload.includes(`["${kind}",`), `missing utility action mapping for ${kind}`); + assert.ok(css.includes(`[data-dream-dog-action="${kind}"]`), `missing utility sticker for ${kind}`); + } + assert.match( + css, + /happy-coding-dog[^{}]*aside\.app-shell-left-panel[^{}]*data-dream-dog-icon[^{}]*data-dream-dog-project[^{}]*\{[^}]*column-gap:\s*8px\s*!important/s, + "navigation and project rows should keep an 8px gap between icon and label", + ); + assert.match( + css, + /data-dream-dog-action="voice"[^{}]*\{[^}]*column-gap:\s*8px\s*!important/s, + "the bottom voice action should keep its icon away from the label", + ); + }); + + it("turns the output and sources popover into a compact hand-drawn resource note", async () => { + const built = await buildPayload( + "./assets/inject", + "./assets/presets/happy-coding-dog", + ); + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + for (const hook of [ + "data-dream-dog-resource-panel", + "data-dream-dog-resource-header", + "data-dream-dog-resource-add", + "data-dream-dog-resource-row", + "data-dream-dog-resource-view-all", + ]) { + assert.ok(built.payload.includes(hook), `missing resource popover DOM hook ${hook}`); + assert.ok(css.includes(`[${hook}]`), `missing resource popover styling for ${hook}`); + } + assert.match( + css, + /data-dream-dog-resource-panel[^{}]*\{[^}]*border:\s*(?:2|3)px solid var\(--dog-ink\)[^}]*box-shadow:/s, + "the resource popover should read as a bordered paper note", + ); + assert.match( + css, + /data-dream-dog-resource-row[^{}]*\{[^}]*column-gap:\s*8px\s*!important/s, + "resource icons need an 8px gap from their labels", + ); + assert.ok(css.includes('[data-dream-dog-resource-header="output"]')); + assert.ok(css.includes('[data-dream-dog-resource-header="sources"]')); + }); + + it("keeps resource popover colors above the generic elevated-panel treatment", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + const genericPanelRule = css.lastIndexOf('body div[class~="rounded-3xl"][class~="bg-surface-elevated-secondary"]'); + const outputHeaderRule = css.lastIndexOf('[data-dream-dog-resource-header="output"]'); + const sourcesHeaderRule = css.lastIndexOf('[data-dream-dog-resource-header="sources"]'); + const addButtonRule = css.lastIndexOf("[data-dream-dog-resource-add]"); + + assert.ok(outputHeaderRule > genericPanelRule, "the yellow output label must win the cascade"); + assert.ok(sourcesHeaderRule > genericPanelRule, "the coral sources label must win the cascade"); + assert.ok(addButtonRule > genericPanelRule, "the round add stickers must win the cascade"); + assert.match( + css, + /data-dream-dog-resource-panel\]\[class~="rounded-3xl"\][^{}]*data-dream-dog-resource-header[^{}]*class~="sticky"/s, + "resource headers need enough specificity to beat the generic sticky panel header", + ); + }); + + it("recognizes the resource add controls even when they expose an expanded state", async () => { + const built = await buildPayload( + "./assets/inject", + "./assets/presets/happy-coding-dog", + ); + + assert.match( + built.payload, + /filter\(\(button\) => !button\.classList\.contains\("group\/section-toggle"\)\)/, + "only the section toggle should be excluded from add-button styling", + ); + }); + + it("maps the hand-painted treatment to every major Codex shell region", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + const scope = 'html.codex-dream-skin[data-dream-theme="happy-coding-dog"]'; + const requiredSelectors = [ + `${scope} body`, + `${scope} aside.app-shell-left-panel`, + `${scope} main.dream-skin-main-surface`, + `${scope} header.app-header-tint`, + `${scope} [data-message-author-role]`, + `${scope} article`, + `${scope} .dream-skin-composer`, + `${scope} pre`, + `${scope} [class*="_ArtifactPanel_"]`, + ]; + + for (const selector of requiredSelectors) { + assert.ok(css.includes(selector), `missing scoped Happy Coding Dog treatment for ${selector}`); + } + }); + + it("keeps the painted title bar and composer decoration anchored against generic rules", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + const scope = 'html.codex-dream-skin[data-dream-theme="happy-coding-dog"]'; + assert.ok( + css.includes(`${scope} main.dream-skin-main-surface > header.app-header-tint`), + "title bar override must outrank the generic main/header selector", + ); + assert.match( + css, + /data-dream-theme="happy-coding-dog"\][^{}]*\.dream-skin-composer[^{}]*\{[^}]*position:\s*relative\s*!important;/s, + "composer must anchor its painted star decoration", + ); + }); + + it("keeps scrolled conversation content behind the cream thread header and ribbon", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + assert.match( + css, + /happy-coding-dog[^{}]*main\.dream-skin-main-surface:not\(\.dream-skin-home-shell\)\s*>\s*header\[class~="fixed"\]\[class~="z-30"\][^{}]*\{[^}]*background:[^}]*100% 6px no-repeat[^}]*var\(--dog-cream\)\s*!important[^}]*border-bottom:\s*3px solid var\(--dog-ink\)/s, + "the fixed thread header must use opaque cream paper with a narrow painted ribbon", + ); + }); + + it("does not place a paper fade over the top of populated conversations", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + assert.doesNotMatch( + css, + /main\.dream-skin-main-surface:not\(\.dream-skin-home-shell\)::after\s*\{[^}]*content:\s*""[^}]*top:\s*46px[^}]*height:\s*44px/s, + "the conversation background must remain visible immediately below the fixed toolbar", + ); + }); + + it("keeps only the upper titlebar rule on populated task conversations", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + assert.match( + css, + /#codex-dream-skin-chrome:not\(\.dream-skin-home-shell\)::before[^{}]*\{[^}]*background:\s*var\(--dog-dopamine-header\)\s*!important[^}]*border-bottom:\s*0\s*!important[^}]*box-shadow:\s*none\s*!important/s, + ); + assert.match( + css, + /main:not\(\.dream-skin-home-shell\)\s*\[class\*="_MainContentViewport_"\]::after[^{}]*\{[^}]*background:\s*var\(--dog-dopamine-header\)\s*!important/s, + ); + }); + + it("keeps only the upper titlebar rule on the new-conversation home", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + assert.match( + css, + /#codex-dream-skin-chrome\.dream-skin-home-shell::before[^{}]*\{[^}]*background:\s*transparent\s*!important[^}]*border-bottom:\s*0\s*!important[^}]*box-shadow:\s*none\s*!important/s, + ); + assert.match( + css, + /main\.dream-skin-home-shell\s*\[class\*="_MainContentViewport_"\]::after[^{}]*\{[^}]*background:\s*transparent\s*!important[^}]*border-bottom:\s*0\s*!important/s, + ); + }); + + it("covers the complete live Codex workspace instead of only the home preview", () => { + const css = fs.readFileSync(path.join(process.cwd(), "assets/inject/dream-skin.css"), "utf8"); + const requiredWorkspaceHooks = [ + "[class*=_Thread]", + "[class*=_Conversation]", + "[class*=_Output]", + "[class*=_Sources]", + "[class*=_ComposerLayoutRoot_]", + "[data-radix-scroll-area-viewport]", + "--dog-stroke-texture", + ]; + + for (const hook of requiredWorkspaceHooks) { + assert.match(css, new RegExp(hook.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))); + } + }); + + it("does not clip the painted composer outline, stamp, or hard shadow", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + assert.match( + css, + /happy-coding-dog[^}]*\}[\s\S]*\[class\*=_ComposerLayoutRoot_\]\.dream-skin-composer-dock\s*\{[^}]*overflow:\s*visible\s*!important/, + ); + assert.match( + css, + /happy-coding-dog[^}]*\}[\s\S]*\.dream-skin-composer-stamp\s*\{[^}]*border:\s*3px solid var\(--dog-ink\)/, + ); + }); + + it("keeps native suggestion glyphs intact while painting their icon container", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + assert.match( + css, + /happy-coding-dog[^}]*home-suggestions[^}]*span:has\(> svg\)[^{]*\{[^}]*border:\s*2px solid var\(--dog-ink\)/s, + "the painted circle belongs on the icon container", + ); + assert.match( + css, + /happy-coding-dog[^}]*home-suggestions[^}]*button svg[^}]*\{[^}]*width:\s*20px[^}]*height:\s*20px[^}]*padding:\s*0/s, + "the SVG viewport must remain unpadded so native glyphs are not clipped", + ); + }); + + it("aligns the home title and suggestion cards to one centered content rail", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + assert.match( + css, + /happy-coding-dog[^}]*dream-skin-happy-home-title[^}]*group\\\/home-suggestions[^}]*\{[^}]*width:\s*min\(720px, calc\(100% - 48px\)\)[^}]*margin-inline:\s*auto[^}]*transform:\s*none\s*!important/s, + "the title and cards must share a centered rail without a viewport-relative offset", + ); + }); + + it("renders aligned fallback suggestions when Codex leaves the native host empty", async () => { + const built = await buildPayload( + "./assets/inject", + "./assets/presets/happy-coding-dog", + ); + + assert.ok( + built.payload.includes("dream-skin-happy-fallback-suggestions"), + "the live skin must provide cards when the native suggestion host is empty", + ); + assert.ok( + built.payload.includes('data-happy-suggestion="understand"'), + "the fallback must expose actionable suggestion buttons", + ); + assert.ok( + built.payload.includes('querySelector(\':scope > [class*="top-full"]\')'), + "the fallback must reuse Codex's title-owned suggestion host", + ); + assert.match( + built.payload, + /dream-skin-happy-fallback-suggestions[^{}]*\{[^}]*position:\s*absolute\s*!important/s, + "the fallback must preserve the native absolute-positioned host", + ); + }); + + it("does not decorate the full home wrapper as the voice card", async () => { + const built = await buildPayload( + "./assets/inject", + "./assets/presets/happy-coding-dog", + ); + + assert.match( + built.payload, + /if \(voiceCard && isHappyVoiceCardCandidate\(voiceCard\)\)\s*\{\s*voiceCard\.classList\.add\("dream-skin-happy-home-voice"\)/, + "the initial voice-label candidate must satisfy the compact-card bounds before decoration", + ); + }); + + it("removes the native white top fade from the animal home canvas", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + assert.match( + css, + /happy-coding-dog[^{}]*dream-skin-home-shell[^{}]*\[class\*="_MainContentTopFade_"\][^{}]*\{[^}]*display:\s*none\s*!important/s, + "the native white-to-transparent top fade must not sit above the painted background", + ); + }); + + it("paints the home titlebar while leaving the removed cover layers transparent", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + + assert.match( + css, + /happy-coding-dog[^{}]*main\.dream-skin-home-shell\s*>\s*header\[class~="fixed"\]\[class~="z-30"\][^{}]*\{[^}]*linear-gradient\(100deg[^}]*#ffd84a[^}]*#ff5b49[^}]*#23b7c9[^}]*#78c64b[^}]*#a86be8[^}]*border-bottom:\s*3px solid var\(--dog-ink\)/s, + "the fixed home titlebar must keep the hand-painted multicolor treatment", + ); + assert.match( + css, + /--dog-dopamine-header:\s*linear-gradient\([^;]*#ffd84a[^;]*#ff8a3d[^;]*#ff5b49[^;]*#a86be8[^;]*\);/s, + "the header palette must progress from yellow through orange and coral to purple", + ); + assert.doesNotMatch( + css, + /--dog-dopamine-header:[^;]*(?:#2ab1c5|#67d1df|#8eddea|var\(--dog-blue\)|var\(--dog-cyan\))/s, + "the dopamine header must not contain cyan paint", + ); + assert.match( + css, + /happy-coding-dog[^{}]*dream-skin-home-shell[^{}]*\.dream-skin-brand[^{}]*\{[^}]*background:\s*var\(--dog-cream\)[^}]*border:\s*3px solid var\(--dog-coral\)/s, + "the home brand must read as a warm cream-and-coral sticker", + ); + assert.match( + css, + /happy-coding-dog[^{}]*dream-skin-home-shell[^{}]*\.dream-skin-status[^{}]*\{[^}]*background:\s*var\(--dog-yellow\)[^}]*box-shadow:\s*3px 3px 0 var\(--dog-purple\)/s, + "the online status must use yellow paint with a purple sticker shadow", + ); + assert.match( + css, + /#codex-dream-skin-chrome\.dream-skin-home-shell::before[^{}]*\{[^}]*background:\s*transparent\s*!important/s, + "the removed home cover must stay transparent", + ); + }); + + it("uses the edge-blended animal team artwork without canvas gutters", () => { + const css = fs.readFileSync(path.resolve("assets/inject/dream-skin.css"), "utf8"); + const theme = JSON.parse( + fs.readFileSync(path.resolve("assets/presets/happy-coding-dog/theme.json"), "utf8"), + ); + + assert.equal(theme.hero, "hero-workspace-blended.png"); + assert.match( + css, + /happy-coding-dog[^{}]*dream-skin-native-home-dog[^{}]*\{[^}]*object-fit:\s*cover\s*!important[^}]*object-position:\s*center\s*!important/s, + "the workspace-specific artwork must fill the canvas without a side color block", + ); + assert.match( + css, + /happy-coding-dog[^{}]*dream-skin-happy-home-canvas[^{}]*\{[^}]*scrollbar-gutter:\s*auto\s*!important/s, + "the home canvas must not reserve side gutters around the artwork", + ); }); }); diff --git a/electron/engine/verify.ts b/electron/engine/verify.ts index a385a77..2ad57e5 100644 --- a/electron/engine/verify.ts +++ b/electron/engine/verify.ts @@ -86,7 +86,10 @@ export async function verifySession(session: CdpSession): Promise const value = box(node); return Boolean(value?.visible && node.getClientRects().length > 0); }; - const shellMain = document.querySelector('main.main-surface') ?? document.querySelector('main'); + const shellMain = document.querySelector('main.main-surface') ?? + document.querySelector('main.dream-skin-main-surface') ?? + document.querySelector('main[class*="_MainContentSurface_"]') ?? + document.querySelector('main'); const homeCandidates = shellMain ? [ ...(shellMain.matches('[role="main"]') ? [shellMain] : []), @@ -104,7 +107,8 @@ export async function verifySession(session: CdpSession): Promise visible(candidate.querySelector('.group\\\\/home-suggestions')); return visible(candidate) && hasHomeContent && !hasVisibleTaskContent; }) ?? null; - const home = document.querySelector('[role="main"].dream-skin-home'); + const home = document.querySelector('[role="main"].dream-skin-home') ?? + document.querySelector('.dream-skin-role-main.dream-skin-home'); const blueWindowHome = home?.querySelector('#codex-dream-skin-blue-window-home') ?? null; const suggestions = blueWindowHome?.querySelector('.blue-window-home__quick-actions') ?? home?.querySelector('.group\\\\/home-suggestions') ?? null; @@ -115,7 +119,10 @@ export async function verifySession(session: CdpSession): Promise const projectButton = box(blueWindowHome?.querySelector('[data-project-target]')) ?? box(home?.querySelector('.group\\\\/project-selector > button')); const composer = box(blueWindowHome?.querySelector('.blue-window-home__composer')) ?? - box(document.querySelector('.composer-surface-chrome')); + box(document.querySelector('.composer-surface-chrome')) ?? + box(document.querySelector('.dream-skin-composer')) ?? + box(document.querySelector('[class*="_ComposerLayoutRoot_"]')) ?? + box(document.querySelector('.ProseMirror')?.closest('[class]')); const sidebar = box(document.querySelector('aside.app-shell-left-panel')); const chrome = document.getElementById('codex-dream-skin-chrome'); const result = { diff --git a/electron/ipc.ts b/electron/ipc.ts index a30de21..b9be8cb 100644 --- a/electron/ipc.ts +++ b/electron/ipc.ts @@ -10,6 +10,7 @@ import os from "node:os"; import path from "node:path"; import type { AiThemeMessageInput, + ApplyThemeOptions, CustomThemeInput, InspectedThemePackage, OpenThemeAction, @@ -128,7 +129,7 @@ export function registerIpc(ctx: IpcContext): void { ipcMain.handle("themes:list", () => store.listThemes()); - ipcMain.handle("themes:apply", (_event, id: string, opts?: { confirmRestart?: boolean }) => + ipcMain.handle("themes:apply", (_event, id: string, opts?: ApplyThemeOptions) => controller.applyTheme(id, opts), ); diff --git a/electron/preload.ts b/electron/preload.ts index f6365fc..4716e75 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -8,6 +8,7 @@ import type { AiThemeJob, AppState, AppUpdateState, + ApplyThemeOptions, AuthState, CodexApprovalRequest, CodexThemesApi, @@ -42,7 +43,7 @@ const api: CodexThemesApi = { openAppUpdateRelease: () => ipcRenderer.invoke("updater:openRelease"), openAppUpdateDownload: () => ipcRenderer.invoke("updater:openDownload"), listThemes: () => ipcRenderer.invoke("themes:list"), - applyTheme: (id: string, opts?: { confirmRestart?: boolean }) => + applyTheme: (id: string, opts?: ApplyThemeOptions) => ipcRenderer.invoke("themes:apply", id, opts), restoreOfficial: () => ipcRenderer.invoke("themes:restoreOfficial"), openCodex: () => ipcRenderer.invoke("codex:open"), diff --git a/electron/shared/types.ts b/electron/shared/types.ts index c4638b5..11643c5 100644 --- a/electron/shared/types.ts +++ b/electron/shared/types.ts @@ -581,6 +581,11 @@ export interface AppState { export type ApplyStatus = "applied" | "partial" | "failed"; +export interface ApplyThemeOptions { + confirmRestart?: boolean; + source?: ThemeSource; +} + export interface ApplyResult { ok: boolean; status: ApplyStatus; @@ -988,7 +993,7 @@ export interface CodexThemesApi { openAppUpdateRelease(): Promise; openAppUpdateDownload(): Promise; listThemes(): Promise; - applyTheme(id: string, opts?: { confirmRestart?: boolean }): Promise; + applyTheme(id: string, opts?: ApplyThemeOptions): Promise; restoreOfficial(): Promise<{ ok: boolean; error?: string }>; openCodex(): Promise<{ ok: boolean; error?: string }>; selectCodexDesktop(): Promise; diff --git a/electron/themes/store.ts b/electron/themes/store.ts index dd6167b..7fad2f6 100644 --- a/electron/themes/store.ts +++ b/electron/themes/store.ts @@ -59,6 +59,8 @@ export interface StorePaths { export interface ResolveThemeDirOptions { /** Prefer a downloaded marketplace package over a bundled catalog placeholder. */ preferPurchased?: boolean; + /** Prefer the library source selected in the renderer when duplicate ids exist. */ + preferredSource?: ThemeSource; /** Catalog-only packages are previews and must never be applied to Codex. */ allowCatalogOnly?: boolean; } @@ -202,9 +204,19 @@ export class ThemeStore { /** Resolve a theme id to its directory. Library operations keep preset-first compatibility. */ async resolveThemeDir(id: string, options: ResolveThemeDirOptions = {}): Promise { - const roots = options.preferPurchased && this.paths.purchasedThemesRoot + const sourceRoots: Record = { + preset: this.paths.presetsRoot, + custom: this.paths.userThemesRoot, + imported: this.paths.userThemesRoot, + purchased: this.paths.purchasedThemesRoot, + }; + const preferredRoot = options.preferredSource ? sourceRoots[options.preferredSource] : undefined; + const fallbackRoots = options.preferPurchased && this.paths.purchasedThemesRoot ? [this.paths.purchasedThemesRoot, this.paths.userThemesRoot, this.paths.presetsRoot] : [this.paths.presetsRoot, this.paths.userThemesRoot, ...(this.paths.purchasedThemesRoot ? [this.paths.purchasedThemesRoot] : [])]; + const roots = preferredRoot + ? [preferredRoot, ...fallbackRoots.filter((root) => root !== preferredRoot)] + : fallbackRoots; for (const root of roots) { let entries: string[] = []; try { diff --git a/package-lock.json b/package-lock.json index a7e74c5..7a8abf2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "codex-themes", - "version": "0.2.15", + "version": "0.2.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codex-themes", - "version": "0.2.15", + "version": "0.2.17", "license": "MIT", "dependencies": { "@supabase/supabase-js": "^2.110.8", diff --git a/package.json b/package.json index f2d620a..ce5c954 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codex-themes", - "version": "0.2.15", + "version": "0.2.17", "description": "Desktop theme manager for the OpenAI Codex desktop app (CDP injection, no patching)", "type": "module", "main": "dist/main/index.js", @@ -14,7 +14,7 @@ "preview": "electron-vite preview", "preview:web": "astro preview --root web", "typecheck": "tsc -p tsconfig.node.json --noEmit && tsc -p tsconfig.server.json --noEmit && tsc -p tsconfig.web.json --noEmit && astro check --root web", - "test": "esbuild electron/deep-links.test.ts electron/updater-state.test.ts electron/updater-platform.test.ts electron/update-install.test.ts electron/engine/cdp.test.ts electron/engine/theme.test.ts electron/engine/layout-catalog.test.ts electron/ai/ai.test.ts electron/engine/package-safety.test.ts electron/codex-cli/locator.test.ts electron/platform/index.test.ts electron/platform/codex-windows.test.ts electron/gallery-themes.test.ts electron/commerce/config.test.ts server/commerce-api/alipay.test.ts server/commerce-api/avatar.test.ts server/commerce-api/theme-package.test.ts server/downloads/github-release.test.ts --bundle --platform=node --format=esm --external:adm-zip --external:alipay-sdk --external:sharp --alias:electron=./electron/test-stubs/electron-stub.ts --outdir=tmp/tests --out-extension:.js=.mjs && node --test \"tmp/tests/**/*.test.mjs\" scripts/publish-paid-theme.test.mjs scripts/package-macos.test.mjs scripts/package-windows.test.mjs scripts/merge-macos-metadata.test.mjs", + "test": "esbuild electron/controller.test.ts electron/deep-links.test.ts electron/updater-state.test.ts electron/updater-platform.test.ts electron/update-install.test.ts electron/engine/cdp.test.ts electron/engine/theme.test.ts electron/engine/layout-catalog.test.ts electron/ai/ai.test.ts electron/engine/package-safety.test.ts electron/codex-cli/locator.test.ts electron/platform/index.test.ts electron/platform/codex-windows.test.ts electron/gallery-themes.test.ts electron/commerce/config.test.ts server/commerce-api/alipay.test.ts server/commerce-api/avatar.test.ts server/commerce-api/theme-package.test.ts server/downloads/github-release.test.ts --bundle --platform=node --format=esm --external:adm-zip --external:alipay-sdk --external:sharp --alias:electron=./electron/test-stubs/electron-stub.ts --outdir=tmp/tests --out-extension:.js=.mjs && node --test \"tmp/tests/**/*.test.mjs\" scripts/publish-paid-theme.test.mjs scripts/package-macos.test.mjs scripts/package-windows.test.mjs scripts/merge-macos-metadata.test.mjs", "gen:presets": "node scripts/gen-presets.mjs", "verify:machine": "esbuild scripts/verify-real-machine.mts --bundle --platform=node --format=esm --external:adm-zip --outfile=tmp/verify-real-machine.mjs && node tmp/verify-real-machine.mjs", "dist": "electron-vite build && node scripts/build-dist.mjs", diff --git a/scripts/build-standalone-happy-coding.mjs b/scripts/build-standalone-happy-coding.mjs new file mode 100644 index 0000000..db14c40 --- /dev/null +++ b/scripts/build-standalone-happy-coding.mjs @@ -0,0 +1,114 @@ +import { execFile } from "node:child_process"; +import fs from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { promisify } from "node:util"; +import AdmZip from "adm-zip"; + +const execFileAsync = promisify(execFile); +const defaultProjectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + +function executableEntry(zip, name, data) { + zip.addFile(name, data, "", 0o755); +} + +function installScript() { + return `#!/bin/zsh +set -euo pipefail +SOURCE_DIR="\${0:A:h}/runtime" +INSTALL_DIR="\${HOME}/Library/Application Support/Happy Coding Theme" +AGENT_FILE="\${HOME}/Library/LaunchAgents/com.happycoding.theme.plist" +LABEL="com.happycoding.theme" + +mkdir -p "\${INSTALL_DIR}" "\${HOME}/Library/LaunchAgents" +/usr/bin/ditto "\${SOURCE_DIR}" "\${INSTALL_DIR}" +/bin/chmod 755 "\${INSTALL_DIR}/happy-coding-runtime" + +/bin/launchctl bootout "gui/\${UID}/\${LABEL}" >/dev/null 2>&1 || true +/bin/cat > "\${AGENT_FILE}" < + + +Label\${LABEL} +ProgramArguments\${INSTALL_DIR}/happy-coding-runtime--watch +RunAtLoadKeepAlive +StandardOutPath\${INSTALL_DIR}/runtime.log +StandardErrorPath\${INSTALL_DIR}/runtime-error.log + +PLIST +/bin/launchctl bootstrap "gui/\${UID}" "\${AGENT_FILE}" +/bin/launchctl kickstart -k "gui/\${UID}/\${LABEL}" +/usr/bin/osascript -e 'display dialog "Happy Coding 已安装并开始应用。Codex 可能会自动重启一次。" buttons {"好"} default button "好" with title "Happy Coding"' +`; +} + +function uninstallScript() { + return `#!/bin/zsh +set -euo pipefail +INSTALL_DIR="\${HOME}/Library/Application Support/Happy Coding Theme" +AGENT_FILE="\${HOME}/Library/LaunchAgents/com.happycoding.theme.plist" +LABEL="com.happycoding.theme" + +/bin/launchctl bootout "gui/\${UID}/\${LABEL}" >/dev/null 2>&1 || true +if [[ -x "\${INSTALL_DIR}/happy-coding-runtime" ]]; then + "\${INSTALL_DIR}/happy-coding-runtime" --cleanup || true +fi +/bin/rm -f "\${AGENT_FILE}" +/bin/rm -rf "\${INSTALL_DIR}" +/usr/bin/osascript -e 'display dialog "Happy Coding 已卸载,Codex 已恢复官方外观。" buttons {"好"} default button "好" with title "Happy Coding"' +`; +} + +export async function buildStandaloneThemePackage({ + projectRoot = defaultProjectRoot, + outputDir = path.join(projectRoot, "output", "standalone"), + runtimePath, + archiveName = "Happy-Coding-macOS-arm64.zip", +} = {}) { + const themeDir = path.join(projectRoot, "assets", "presets", "happy-coding-dog"); + const injectDir = path.join(projectRoot, "assets", "inject"); + const manifest = JSON.parse(await fs.readFile(path.join(themeDir, "theme.json"), "utf8")); + const runtime = runtimePath ?? path.join(outputDir, "happy-coding-runtime"); + + await fs.mkdir(outputDir, { recursive: true }); + if (!runtimePath) { + const bun = path.join(process.env.HOME ?? "", ".bun", "bin", "bun"); + await execFileAsync(bun, [ + "build", + path.join(projectRoot, "standalone", "happy-coding-runtime.ts"), + "--compile", + "--target=bun-darwin-arm64", + `--outfile=${runtime}`, + ]); + } + + const zip = new AdmZip(); + const prefix = "Happy Coding/"; + executableEntry(zip, `${prefix}Install Happy Coding.command`, Buffer.from(installScript())); + executableEntry(zip, `${prefix}Uninstall Happy Coding.command`, Buffer.from(uninstallScript())); + executableEntry(zip, `${prefix}runtime/happy-coding-runtime`, await fs.readFile(runtime)); + zip.addLocalFile(path.join(injectDir, "dream-skin.css"), `${prefix}runtime/inject`); + zip.addLocalFile(path.join(injectDir, "renderer-inject.js"), `${prefix}runtime/inject`); + zip.addLocalFile(path.join(themeDir, "theme.json"), `${prefix}runtime/theme`); + + const themeAssets = new Set([manifest.hero, manifest.preview, manifest.wallpaper, manifest.stamp].filter(Boolean)); + for (const asset of themeAssets) { + zip.addLocalFile(path.join(themeDir, asset), `${prefix}runtime/theme`); + } + zip.addFile(`${prefix}package.json`, Buffer.from(`${JSON.stringify({ + name: "Happy Coding", + themeId: manifest.id, + themeVersion: manifest.version, + engineVersion: "1.2.4", + platform: "darwin-arm64", + }, null, 2)}\n`)); + + const archivePath = path.join(outputDir, archiveName); + zip.writeZip(archivePath); + return { archivePath }; +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + const result = await buildStandaloneThemePackage(); + console.log(result.archivePath); +} diff --git a/scripts/build-standalone-happy-coding.test.mjs b/scripts/build-standalone-happy-coding.test.mjs new file mode 100644 index 0000000..6707ac5 --- /dev/null +++ b/scripts/build-standalone-happy-coding.test.mjs @@ -0,0 +1,65 @@ +import assert from "node:assert/strict"; +import { execFile } from "node:child_process"; +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import test from "node:test"; +import { promisify } from "node:util"; +import AdmZip from "adm-zip"; + +import { buildStandaloneThemePackage } from "./build-standalone-happy-coding.mjs"; + +const execFileAsync = promisify(execFile); + +test("builds an independent Happy Coding macOS package", async () => { + const root = await fs.mkdtemp(path.join(os.tmpdir(), "happy-coding-package-test-")); + const fakeRuntime = path.join(root, "happy-coding-runtime"); + await fs.writeFile(fakeRuntime, "runtime", { mode: 0o755 }); + + const result = await buildStandaloneThemePackage({ + projectRoot: process.cwd(), + outputDir: root, + runtimePath: fakeRuntime, + archiveName: "Happy-Coding-test.zip", + }); + + const zip = new AdmZip(result.archivePath); + const names = zip.getEntries().map((entry) => entry.entryName).sort(); + assert.ok(names.includes("Happy Coding/Install Happy Coding.command")); + assert.ok(names.includes("Happy Coding/Uninstall Happy Coding.command")); + assert.ok(names.includes("Happy Coding/runtime/happy-coding-runtime")); + assert.ok(names.includes("Happy Coding/runtime/inject/dream-skin.css")); + assert.ok(names.includes("Happy Coding/runtime/inject/renderer-inject.js")); + assert.ok(names.includes("Happy Coding/runtime/theme/theme.json")); + assert.ok(names.includes("Happy Coding/runtime/theme/hero-workspace-blended.png")); + assert.ok(names.includes("Happy Coding/runtime/theme/wallpaper.png")); + assert.ok(names.includes("Happy Coding/runtime/theme/stamp.png")); + + const install = zip.readAsText("Happy Coding/Install Happy Coding.command"); + assert.match(install, /com\.happycoding\.theme/); + assert.match(install, /LaunchAgents/); + assert.match(install, /KeepAlive/); + assert.match(install, /happy-coding-runtime/); + + const uninstall = zip.readAsText("Happy Coding/Uninstall Happy Coding.command"); + assert.match(uninstall, /--cleanup/); + assert.match(uninstall, /bootout/); + + const extracted = path.join(root, "extracted"); + await fs.mkdir(extracted); + await execFileAsync("/usr/bin/unzip", ["-q", result.archivePath, "-d", extracted]); + for (const relative of [ + "Happy Coding/Install Happy Coding.command", + "Happy Coding/Uninstall Happy Coding.command", + "Happy Coding/runtime/happy-coding-runtime", + ]) { + const mode = (await fs.stat(path.join(extracted, relative))).mode; + assert.notEqual(mode & 0o111, 0, `${relative} must remain executable after extraction`); + } + + const manifest = JSON.parse(zip.readAsText("Happy Coding/package.json")); + assert.equal(manifest.name, "Happy Coding"); + assert.equal(manifest.themeId, "happy-coding-dog"); + assert.equal(manifest.engineVersion, "1.2.4"); + assert.equal(manifest.platform, "darwin-arm64"); +}); diff --git a/src/components/ThemeCard.tsx b/src/components/ThemeCard.tsx index 2d960a8..c6e56cb 100644 --- a/src/components/ThemeCard.tsx +++ b/src/components/ThemeCard.tsx @@ -120,7 +120,7 @@ export function ThemeCard({