@import "tailwindcss"; @import "@chopin/visuals/theme.css"; @import "./conversation-plan/source.css"; /* * Sibling packages that build on these utilities. * * They are reached through workspace symlinks, which Tailwind's automatic * content detection skips — without these the classes in the editor and the * questionnaire views resolve to nothing at all, silently. * `.ts` is included because shared class lists can live outside components. */ @source "../../../packages/editor/src/**/*.{ts,tsx}"; @source "../../../packages/question/src/**/*.{ts,tsx}"; @utility ring-hairline { outline: var(--edge-width) solid var(--color-edge); outline-offset: calc(-1 * var(--edge-width)); } :where([data-nucleo-icon]) { color: var(--color-icon); } @utility icon-danger { --color-icon: var(--color-danger-icon); } :where(.btn-primary, .btn-destructive) [data-nucleo-icon] { color: inherit; } @utility control-edge { border: var(--edge-width) solid var(--color-control-edge); &:disabled { border-color: var(--color-edge); } } @utility btn { display: inline-flex; align-items: center; justify-content: center; gap: calc(var(--spacing) * 2); border: 0; border-radius: var(--radius-md); font-size: var(--text-sm); font-weight: 500; white-space: nowrap; &:disabled { cursor: default; opacity: 0.4; } &[aria-busy="true"]:disabled { opacity: 0.65; } &[aria-busy="true"] [data-button-loader] { animation: button-loader-spin 800ms linear infinite; } } @keyframes button-loader-spin { to { transform: rotate(360deg); } } @utility btn-md { height: 2rem; padding-inline: calc(var(--spacing) * 3); } @utility btn-sm { height: 1.5rem; padding-inline: calc(var(--spacing) * 2); } @utility btn-icon { width: 1.75rem; height: 1.75rem; padding: 0.4375rem; } @utility btn-primary { background-color: var(--color-brand); box-shadow: var(--shadow-resting); color: var(--color-page); outline: var(--button-edge-width) solid var(--color-control-edge); outline-offset: calc(-1 * var(--button-edge-width)); &:hover:not(:disabled) { background-color: var(--color-brand-hover); } &:active:not(:disabled) { background-color: var(--color-brand-active); } } @utility btn-secondary { background-color: var(--color-gray-200); color: var(--color-text-primary); outline: var(--button-edge-width) solid var(--color-edge); outline-offset: calc(-1 * var(--button-edge-width)); &:hover:not(:disabled) { background-color: var(--color-gray-300); } &:active:not(:disabled) { background-color: var(--color-gray-400); } } @utility btn-outline { background-color: var(--color-page); color: var(--color-text-primary); outline: var(--button-edge-width) solid var(--color-control-edge); outline-offset: calc(-1 * var(--button-edge-width)); box-shadow: var(--shadow-resting); &:hover:not(:disabled) { background-color: var(--color-inset); } &:active:not(:disabled) { background-color: var(--color-gray-200); box-shadow: none; } } @utility btn-outline-danger { background-color: transparent; color: var(--color-danger-text); outline: var(--button-edge-width) solid var(--color-danger-edge); outline-offset: calc(-1 * var(--button-edge-width)); &:hover:not(:disabled) { background-color: var(--color-danger-surface-hover); } &:active:not(:disabled) { background-color: var(--color-danger-surface-active); } } @utility btn-ghost { background-color: transparent; color: var(--color-text-secondary); &:hover:not(:disabled) { background-color: var(--color-gray-200); } &:active:not(:disabled) { background-color: var(--color-gray-300); } } @utility btn-destructive { background-color: var(--color-destructive); color: var(--color-page); outline: var(--button-edge-width) solid var(--color-control-edge); outline-offset: calc(-1 * var(--button-edge-width)); &:hover:not(:disabled) { background-color: var(--color-destructive-hover); } &:active:not(:disabled) { background-color: var(--color-destructive-active); } } @utility field { border: var(--edge-width) solid var(--color-control-edge); border-radius: var(--radius-md); background-color: var(--color-page); box-shadow: var(--shadow-resting); color: var(--color-text-primary); &:disabled { border-color: var(--color-edge); background-color: var(--color-gray-200); color: var(--color-gray-600); } &[aria-invalid="true"] { border-color: var(--color-destructive); outline: 2px solid var(--color-destructive); outline-offset: 2px; } } @utility field-ghost { border: var(--edge-width) solid transparent; border-radius: var(--radius-md); background-color: transparent; color: var(--color-text-primary); &:hover:not(:disabled) { border-color: var(--color-control-edge); } &:disabled { border-color: var(--color-edge); background-color: var(--color-gray-200); color: var(--color-gray-600); } } @utility choice-control { appearance: none; border: var(--edge-width) solid var(--color-control-edge); background-color: var(--color-page); color: var(--color-text-primary); &[type="radio"] { border-radius: var(--radius-full); } &[type="checkbox"] { border-radius: var(--radius-sm); } &:checked { border-color: var(--color-brand); background-color: var(--color-brand); } &[type="radio"]:checked { border-width: calc(var(--edge-width) * 2); box-shadow: inset 0 0 0 3px var(--color-page); } &[type="checkbox"]:checked { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m3 7 2.5 2.5L11 4'/%3E%3C/svg%3E"); } &:disabled { border-color: var(--color-edge); background-color: var(--color-gray-200); color: var(--color-gray-600); } &:disabled:checked { background-color: var(--color-gray-600); } &[type="radio"]:disabled:checked { box-shadow: inset 0 0 0 3px var(--color-gray-200); } &[type="checkbox"]:disabled:checked { background-color: var(--color-gray-200); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='%23605e56' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m3 7 2.5 2.5L11 4'/%3E%3C/svg%3E"); } } /* Extra contrast is an opt-in accommodation, not the normal control edge. */ @media (prefers-contrast: more) { :where(.control-edge, .field, .choice-control):not([aria-invalid="true"]) { outline: var(--edge-width) solid var(--color-control-boundary); outline-offset: calc(-1 * var(--edge-width)); } :where(.control-edge, .field, .choice-control):disabled { outline-color: var(--color-edge); } } @utility hairline-t { border-top: var(--edge-width) solid var(--color-edge); } @utility hairline-r { border-right: var(--edge-width) solid var(--color-edge); } @utility hairline-b { border-bottom: var(--edge-width) solid var(--color-edge); } @utility hairline-l { border-left: var(--edge-width) solid var(--color-edge); } @media (min-resolution: 2dppx) { :root { --edge-width: 0.5px; } } html, body { height: 100%; overflow-x: hidden; } #root { position: fixed; left: var(--app-left, 0px); top: var(--app-top, 0px); width: var(--app-width, 100%); height: 100%; height: var(--app-height, 100dvh); } .motion-dropdown { opacity: 0; transform: scale(var(--dropdown-pre-scale)); transition: opacity var(--dropdown-open-dur) var(--dropdown-ease), transform var(--dropdown-open-dur) var(--dropdown-ease); will-change: opacity, transform; } .motion-dropdown.is-open { opacity: 1; transform: scale(1); } .motion-dropdown.is-closing { pointer-events: none; opacity: 0; transform: scale(var(--dropdown-closing-scale)); transition-duration: var(--dropdown-close-dur); } .motion-popover { opacity: 0; transform: scale(var(--dropdown-pre-scale)); transform-origin: var(--motion-origin-x, 50%) var(--motion-origin-y, 50%); transition: opacity var(--dropdown-open-dur) var(--dropdown-ease), transform var(--dropdown-open-dur) var(--dropdown-ease); will-change: opacity, transform; } .motion-popover.is-open { opacity: 1; transform: scale(1); } .motion-popover.is-closing { pointer-events: none; opacity: 0; transform: scale(var(--dropdown-closing-scale)); transition-duration: var(--dropdown-close-dur); } .motion-popover[data-motion-immediate] { transition: none; } .motion-collapse { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--acc-expand) var(--motion-move); } .motion-collapse-content { min-height: 0; overflow: hidden; opacity: 0; transform: translateY(-4px); transition: opacity var(--acc-expand) var(--motion-move), transform var(--acc-expand) var(--motion-move); } .motion-collapse.is-open { grid-template-rows: 1fr; } .motion-collapse.is-open > .motion-collapse-content { opacity: 1; transform: translateY(0); } .motion-collapse.is-closing { grid-template-rows: 0fr; transition-duration: var(--acc-collapse); } .motion-collapse.is-closing > .motion-collapse-content { opacity: 0; transform: translateY(-4px); transition-duration: var(--acc-collapse); } .motion-feedback[data-motion-feedback="icon"] { transform: none; } .motion-feedback[data-motion-feedback="count"] { transform: none; } .motion-feedback[data-motion-feedback="alert"] { transform: none; } :root[data-motion-input="pointer"] .motion-feedback[data-motion-feedback="icon"] { transition-property: opacity, transform; transition-duration: var(--icon-swap-dur); transition-timing-function: var(--motion-smooth-out); } :root[data-motion-input="pointer"] .motion-feedback[data-motion-feedback="count"] { transition-property: opacity, transform; transition-duration: var(--badge-pop-dur); transition-timing-function: var(--motion-smooth-out); } :root[data-motion-input="pointer"] .motion-feedback[data-motion-feedback="alert"] { transition-property: opacity, transform; transition-duration: var(--toast-open); transition-timing-function: var(--motion-smooth-out); } @starting-style { .motion-feedback[data-motion-feedback="icon"] { opacity: 0; transform: scale(0.96); } .motion-feedback[data-motion-feedback="count"] { opacity: 0; transform: translateY(2px) scale(0.96); } .motion-feedback[data-motion-feedback="alert"] { opacity: 0; transform: translateY(4px); } } /* Live Chat arrivals only; `data-chat-enter` is never set on history. */ [data-chat-enter] { transition: opacity var(--duration-base) var(--motion-smooth-out), transform var(--duration-base) var(--motion-smooth-out); } @starting-style { [data-chat-enter] { opacity: 0; transform: translateY(4px); } } .chat-toggle-icon-sidebar { opacity: 0; } .chat-toggle:is(:hover, :focus-visible) .chat-toggle-icon-default { opacity: 0; } .chat-toggle:is(:hover, :focus-visible) .chat-toggle-icon-sidebar { opacity: 1; } @media (hover: hover) and (pointer: fine) { .chat-header-control { opacity: 0; transition: opacity var(--duration-fast) var(--ease-out); } .chat-header:is(:hover, :focus-within) .chat-header-control { opacity: 1; } } @media (any-pointer: coarse) { .chat-header-control { opacity: 1; } } :root[data-motion-input="pointer"] .chat-toggle-icon { transition: opacity var(--duration-fast) var(--ease-out); } :root[data-motion-input="pointer"] .motion-picker-option { transition: background-color var(--duration-fast) var(--ease-out), scale var(--duration-fast) var(--ease-out); } body { margin: 0; background: var(--color-ground); color: var(--color-text-primary); font-family: var(--font-sans); /* macOS subpixel smoothing thickens Inter past the weight asked for. */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } /* One owner per edge: top chrome owns the top inset, compact navigation the bottom one. */ .room-header { padding-right: calc(0.5rem + env(safe-area-inset-right)); padding-left: calc(0.5rem + env(safe-area-inset-left)); padding-top: calc(0.5rem + env(safe-area-inset-top)); } .hosted-header { height: calc(3.5rem + env(safe-area-inset-top)); padding-right: calc(0.75rem + env(safe-area-inset-right)); padding-left: calc(0.75rem + env(safe-area-inset-left)); padding-top: env(safe-area-inset-top); } .workspace-navigation { padding-right: calc(0.25rem + env(safe-area-inset-right)); padding-bottom: calc(0.25rem + env(safe-area-inset-bottom)); padding-left: calc(0.25rem + env(safe-area-inset-left)); } .workspace-navigation [aria-current="page"] { background-color: var(--color-page); color: var(--color-text-primary); box-shadow: var(--shadow-resting); } /* The split workspace is one elevated surface; its panes only own the divider. */ .workspace-root[data-workspace-mode="split"] .workspace-frame { margin-left: calc(var(--spacing) * 3 + env(safe-area-inset-left)); margin-right: calc(var(--spacing) * 3 + env(safe-area-inset-right)); } .workspace-frame .plan-document { box-shadow: none; } .workspace-frame .workspace-chat-panel { border-color: rgb(0 0 0 / 9%); } .workspace-root[data-workspace-mode="split"] .workspace-chat-panel { --panel-direction: -1; } .workspace-root[data-workspace-mode="split"] .workspace-frame > main { min-width: 9rem; } .motion-panel { opacity: 0; transform: translateX(calc(var(--panel-distance) * var(--panel-direction, 1))); transition: opacity var(--panel-open-dur) var(--motion-smooth-out), transform var(--panel-open-dur) var(--motion-smooth-out); will-change: opacity, transform; } .motion-panel.is-open { opacity: 1; transform: translateX(0); } .motion-panel.is-closing { pointer-events: none; opacity: 0; transform: translateX(calc(var(--panel-distance) * var(--panel-direction, 1))); transition-duration: var(--panel-close-dur); } /* Split Chat is a track: its width moves the document, and Chat slides under its clip. */ .workspace-root[data-workspace-mode="split"] .workspace-chat-panel { width: 0; align-items: flex-end; opacity: 1; transform: none; } .workspace-root[data-workspace-mode="split"] .workspace-chat-panel > * { width: var(--chat-width, 0px); } .workspace-root[data-workspace-mode="split"] .workspace-chat-panel.is-open { width: var(--chat-width, 0px); } .workspace-root[data-workspace-mode="split"] .workspace-chat-panel:not(.is-open) { border-inline-width: 0; } .workspace-root[data-workspace-mode="split"] .workspace-chat-panel[data-pane-moving] { transition: width var(--panel-open-dur) var(--motion-move); } .workspace-root[data-workspace-mode="split"] .workspace-chat-panel.is-closing[data-pane-moving] { transition-duration: var(--panel-close-dur); } /* Compact views are sibling tabs: Chat sits leftmost, so it enters from the left. */ .workspace-root:not([data-workspace-mode="split"]) .workspace-chat-panel { --panel-direction: -1; --panel-distance: var(--page-slide-distance); transition-duration: var(--page-slide-dur); } .workspace-root[data-workspace-travel="back"] { --swap-direction: -1; } .content-swap-stack { display: grid; } .content-swap-stack > :is(.motion-content-swap, .motion-route-swap) { grid-area: 1 / 1; min-width: 0; } .motion-content-swap { opacity: 0; transform: translateX(calc(var(--page-slide-distance) * var(--swap-direction, 1))); transition: opacity var(--page-slide-dur) var(--motion-smooth-out), transform var(--page-slide-dur) var(--motion-smooth-out); will-change: opacity, transform; } .motion-content-swap.is-open { opacity: 1; transform: none; will-change: auto; } .motion-content-swap.is-closing { pointer-events: none; opacity: 0; transform: translateX(calc(var(--page-slide-distance) * var(--swap-direction, 1) * -1)); } /* * Switching documents keeps the header, tabs and Chat frame still. Only the * document body and transcript change: out, then in, never both at once. A * staged route is laid out but unseen while its document syncs. */ .motion-route-swap[data-content-swap-state="staged"] { visibility: hidden; } .motion-route-swap :is([data-workspace-document-swap], [data-chat-stack]) { opacity: 0; transition: opacity var(--route-swap-in-dur) var(--ease-out); } .motion-route-swap.is-open :is([data-workspace-document-swap], [data-chat-stack]) { opacity: 1; } .motion-route-swap.is-closing :is([data-workspace-document-swap], [data-chat-stack]) { transition-duration: var(--route-swap-out-dur); } .workspace-root:not([data-workspace-mode="split"]) .workspace-chat-panel { position: absolute; inset: 0; z-index: 10; } /* * Without the split header row, status lies over the top of the document, and * only while it has something to say. Overlaid rather than inserted, so a * short blip does not push the prose down and back. A quiet dot alone is not * worth a row. */ .workspace-status-row { position: absolute; z-index: 3; inset-block-start: 0; inset-inline: 0; } .workspace-status-row:has(.plan-status:is([data-level="notice"], [data-level="alert"])) { display: flex; min-height: calc(var(--spacing) * 9); align-items: center; padding: calc(var(--spacing) * 1.5) calc(var(--spacing) * 4); border-bottom: var(--edge-width) solid var(--color-edge); background: var(--color-page); } .workspace-status-row .plan-status { flex: 1; } .workspace-status-row .plan-status .btn { margin-inline-start: auto; } .workspace-status-row .plan-status[data-level="quiet"] .plan-status-dot { display: none; } /* Touch has no hover, so the detail a tooltip would carry is written out. */ @media (pointer: coarse) { .workspace-status-row .plan-status-detail { display: block; } } /* Jump-to-source: a tint behind the message that fades; the message itself never moves. */ .chat-message-body[data-chat-source] { isolation: isolate; } .chat-message-body:not(:first-child) > .chat-message-to { margin-top: 4px; } .chat-source-tint { position: absolute; inset: -2px -6px; z-index: -1; border-radius: var(--radius-md); background: var(--color-brand-wash); pointer-events: none; animation: chat-source-tint calc(var(--duration-linger) * 2) var(--ease-out) forwards; } @keyframes chat-source-tint { 0%, 40% { opacity: 1; } 100% { opacity: 0; } } .chat-message-body:has([data-analysis-trigger]) { min-height: calc(var(--spacing) * 7); } .chat-work { min-width: 0; margin-block: 2px 4px; } .chat-work-toggle, .chat-work-static { display: flex; min-height: 30px; max-width: 100%; align-items: center; gap: 7px; padding: 3px 0; border: 0; background: transparent; color: var(--color-text-tertiary); font-size: var(--text-sm); line-height: var(--text-sm--line-height); text-align: left; } .chat-work-toggle { cursor: pointer; } .chat-work-toggle:focus-visible, .chat-tool-call-toggle:focus-visible { outline: 2px solid var(--color-brand); outline-offset: 2px; border-radius: var(--radius-sm); } .chat-work-headline { min-width: 0; color: var(--color-text-secondary); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .chat-work-headline-motion { display: inline-block; animation: chat-work-stage-in var(--duration-base) var(--motion-smooth-out) both; } .chat-work-meta { flex: none; color: var(--color-text-quaternary); font-size: var(--text-xs); white-space: nowrap; } .chat-work-chevron { flex: none; color: var(--color-text-quaternary); } .chat-work-lattice { display: grid; flex: none; grid-template-columns: repeat(3, 3px); gap: 3px; place-content: center; width: 18px; height: 18px; } .chat-work-lattice > span { width: 3px; height: 3px; border-radius: 50%; background: var(--color-brand); animation: chat-work-dot calc(var(--duration-base) * 8) var(--motion-move) infinite; } .chat-work-lattice > span:is(:nth-child(2), :nth-child(4)) { animation-delay: var(--duration-fast); } .chat-work-lattice > span:is(:nth-child(3), :nth-child(5), :nth-child(7)) { animation-delay: var(--duration-base); } .chat-work-lattice > span:is(:nth-child(6), :nth-child(8)) { animation-delay: var(--panel-open-dur); } .chat-work-lattice > span:nth-child(9) { animation-delay: var(--duration-linger); } .chat-tool-list { max-height: 192px; margin: 2px 0 2px 8px; padding: 1px 6px 1px 11px; border-left: 1px solid var(--color-edge); color: var(--color-text-tertiary); font-size: var(--text-xs); list-style: none; overflow-y: auto; } .chat-tool-call-toggle { display: flex; width: 100%; min-height: 28px; align-items: center; gap: 8px; padding: 3px 2px; border: 0; background: transparent; color: var(--color-text-tertiary); font-size: var(--text-xs); text-align: left; } button.chat-tool-call-toggle { cursor: pointer; } .chat-tool-call-details { display: grid; gap: 7px; margin: 0 0 7px 20px; } .chat-tool-call-details[hidden] { display: none; } .chat-tool-data-label { margin-bottom: 3px; color: var(--color-text-quaternary); font-size: var(--text-xs); font-weight: 600; } .chat-tool-call-details pre { max-height: 120px; margin: 0; padding: 7px 8px; border-radius: var(--radius-sm); background: var(--color-inset); color: var(--color-text-secondary); font-size: var(--text-xs); line-height: 16px; white-space: pre-wrap; word-break: break-word; overflow: auto; } @keyframes chat-work-dot { 0%, 100% { opacity: 0.28; transform: scale(0.8); } 50% { opacity: 0.9; transform: scale(1); } } @keyframes chat-work-stage-in { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: translateY(0); } } .chat-composer .field { border-color: var(--color-edge); border-radius: var(--radius-lg); box-shadow: var(--shadow-resting); } .chat-composer .field:focus-within { outline: 2px solid var(--color-brand); outline-offset: 2px; } .chat-composer textarea:focus { outline: none; } .chat-header-control:hover:not(:disabled), .chat-header-control:active:not(:disabled) { background-color: transparent; } .chat-composer .send-action:disabled { background-color: var(--color-brand); color: var(--color-page); } @media (min-width: 640px) { .room-header { padding-right: calc(1.25rem + env(safe-area-inset-right)); padding-left: calc(1.25rem + env(safe-area-inset-left)); padding-top: env(safe-area-inset-top); } .hosted-header { padding-right: calc(1.5rem + env(safe-area-inset-right)); padding-left: calc(1.5rem + env(safe-area-inset-left)); } } @media (min-width: 1200px) { /* The desktop composer keeps the same clearance on each exposed edge. */ .chat-composer { padding-inline: 1rem; padding-bottom: calc(1rem + env(safe-area-inset-bottom)); } } @media (max-width: 639px) { /* Touch-sized header controls and their text labels share a vertical center. */ .room-header { align-items: center; } .room-member-face:nth-child(n+4) { display: none; } .room-member-overflow { display: inline; } .repository-picker-trigger { max-width: min(8rem, 36vw); } } :root[data-plan-coarse-pointer] .room-header :where(button, summary), :root[data-plan-coarse-pointer] .chat-composer button, :root[data-plan-coarse-pointer] .hosted-header button, :root[data-plan-coarse-pointer] .repository-picker-search, :root[data-plan-coarse-pointer] .channel-create-input, :root[data-plan-coarse-pointer] [data-hosted] .btn, :root[data-plan-coarse-pointer] .question-choice-row, :root[data-plan-coarse-pointer] .question-actions button, :root[data-plan-coarse-pointer] :where(button, [role="button"])[data-press="wide"] { min-width: 44px; min-height: 44px; } :root[data-plan-coarse-pointer] .question-choice-row { padding-block: 0.5rem; } /* iOS Safari zooms the page when it focuses a text field under 16px. */ @media (pointer: coarse) { .chat-composer .composer-draft-input[contenteditable], textarea, select, input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], [type="file"]) { font-size: max(1rem, var(--text-sm)); } } /* Small controls keep their look; an invisible 44px target grows around them. */ /* In the components layer so utilities such as `absolute` still win. */ @layer components { :root[data-plan-coarse-pointer] :where(.btn-icon, .btn-sm, .project-sidebar-action, .project-sidebar-document-action) { position: relative; } :root[data-plan-coarse-pointer] :where(.btn-icon, .btn-sm, .project-sidebar-action, .project-sidebar-document-action)::after { content: ""; position: absolute; top: 50%; left: 50%; width: max(100%, 44px); height: max(100%, 44px); transform: translate(-50%, -50%); } /* Beside a comment marker: grow vertically only so the marker keeps its taps. */ :root[data-plan-coarse-pointer] .plan-code-toggle::after { width: 100%; } } .question-field { scroll-margin-block-end: calc(var(--keyboard-inset, 0px) + 1rem); } /* The decision card: a question, lettered options, and a quiet footer. */ .question-card { padding: 1rem 0.5rem 0.75rem; } /* Coloured icon holders: the global icon colour would otherwise win. */ :is(.question-mark, .question-check) [data-nucleo-icon], .question-callout .plan-research-badge [data-nucleo-icon] { color: inherit; } .question-head { display: flex; align-items: flex-start; gap: 0.625rem; padding-inline: 0.5rem; } .question-mark { display: grid; flex: none; place-items: center; inline-size: 1.5rem; block-size: 1.5rem; border-radius: var(--radius-full); background: var(--color-success-wash); color: var(--color-success); } .question-head-text { flex: 1; min-width: 0; } .question-title { /* Centre the first line on the 1.5rem mark, then lift 2px optically. */ margin: calc((1.5rem - 1lh) / 2 - 0.125rem) 0 0; font-size: var(--text-base); line-height: var(--text-lg--line-height); font-weight: 600; color: var(--color-text-primary); overflow-wrap: break-word; text-wrap: pretty; } .question-title-link { font: inherit; } .question-hint { margin: 0.125rem 0 0; font-size: var(--text-xs); line-height: var(--text-xs--line-height); color: var(--color-text-tertiary); } .question-options { display: grid; gap: 0.125rem; min-width: 0; margin: 0.75rem 0 0; padding: 0; border: 0; } .question-option { position: relative; display: flex; align-items: flex-start; gap: 0.625rem; padding: 0.375rem 0.75rem 0.375rem 0.5rem; border-radius: var(--radius-md); font-size: var(--text-sm); line-height: var(--text-sm--line-height); transition: background-color var(--duration-fast) var(--ease-out); } /* The native control stays focusable but unseen; its label row is the target. */ .question-input { appearance: none; position: absolute; inset-block-start: 0; inset-inline-start: 0; inline-size: 1px; block-size: 1px; margin: 0; opacity: 0; } label.question-option:has(.question-input:not(:disabled)) { cursor: pointer; } .question-option:has(.question-input:focus-visible) { outline: var(--focus-ring-width) solid var(--focus-ring-color); outline-offset: var(--focus-ring-offset); } .question-option:has(.question-input:not(:disabled)):hover { background: var(--color-hover); } .question-option:has(.question-input:checked), .question-option:has(.question-input:checked:not(:disabled)):hover, .question-option[data-selected] { background: var(--color-brand-wash); } /* A one-line slot (inherits the label's line height) holding a small tile. */ .question-key { display: flex; flex: none; align-items: center; block-size: 1lh; } /* Same 1.5rem as the header mark, so option text shares the title's left edge. */ .question-key > span { display: grid; place-items: center; inline-size: 1.5rem; block-size: 1.5rem; border-radius: var(--radius-sm); background: var(--color-gray-150); font-size: var(--text-xs); line-height: 1; font-weight: 500; color: var(--color-text-secondary); transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out); } .question-option:has(.question-input:checked) .question-key > span, .question-option[data-selected] .question-key > span { background: var(--color-brand); color: var(--color-white); } /* With a description below, the tile sits 4px under the label's centre (optical). */ .question-option:has(.question-desc) .question-key > span { translate: 0 0.25rem; } .question-text { display: grid; flex: 1; min-width: 0; } .question-label { font-weight: 500; color: var(--color-text-primary); } .question-desc { color: var(--color-text-secondary); } .inline-code { background: var(--color-inset); color: var(--color-text-primary); border-radius: var(--radius-sm); padding: 0.125em 0.3em; font-family: var(--font-mono); font-size: inherit; font-weight: 400; } .question-check { flex: none; display: grid; block-size: 1lh; place-items: center; color: var(--color-brand); opacity: 0; transition: opacity var(--duration-fast) var(--ease-out); } .question-option:has(.question-input:checked) .question-check, .question-option[data-selected] .question-check { opacity: 1; } .question-resolved-meta { margin: 0.75rem 0.5rem 0; font-size: var(--text-xs); color: var(--color-text-tertiary); } .question-add, .question-add .question-key { color: var(--color-text-tertiary); } .question-add .question-key > span { background: var(--color-inset); } :is(.question-add, .question-adding) { align-items: center; padding-block: 0.5rem; } .question-add:hover .question-text, .question-add:hover .question-key { color: var(--color-text-secondary); } /* The add row is a real button, not a label around a hidden input. */ button.question-add { inline-size: 100%; border: 0; background: transparent; text-align: start; cursor: pointer; } button.question-add:not(:disabled):hover { background: var(--color-hover); } button.question-add:focus-visible { outline: var(--focus-ring-width) solid var(--focus-ring-color); outline-offset: var(--focus-ring-offset); } button.question-add:disabled { cursor: default; } /* The new option, shown before the server confirms it. */ .question-pending { opacity: 0.6; } .question-adding { outline: var(--edge-width) solid var(--color-control-edge); outline-offset: calc(-1 * var(--edge-width)); } .question-adding:focus-within { outline-color: var(--color-brand); } .question-field { flex: 1; min-width: 0; padding: 0; border: 0; background: transparent; font: inherit; color: var(--color-text-primary); outline: none; resize: none; field-sizing: content; } .question-field:focus-visible { outline: none; } .question-field::placeholder { color: var(--color-text-tertiary); } .question-card[data-saving] .question-options { opacity: 0.6; } /* Matches the research card: danger badge beside pale-red callout text. */ .plan-research-callout.question-callout { display: flex; align-items: flex-start; gap: 0.5rem; margin: 0.5rem 0.5rem 0; padding: 0.5rem 0.625rem 0.5rem 0.5rem; } .question-callout p { display: grid; } .question-callout strong { font-weight: 500; } .question-actions { display: flex; align-items: center; justify-content: flex-end; gap: 0.375rem; margin-block-start: 0.75rem; padding-inline: 0.5rem; } @media (prefers-reduced-motion: no-preference) { .question-actions > * { animation: question-fade var(--duration-fast) var(--ease-out); } } @keyframes question-fade { from { opacity: 0; } } /* Discard confirm: the footer swaps in place and fades in. */ .question-confirm { margin-inline-end: auto; font-size: var(--text-sm); font-weight: 500; color: var(--color-text-primary); } /* Footer stepper, left: ‹ question name n/m ›, 28px carets and --text-sm. */ .question-stepper { display: inline-flex; min-width: 0; align-items: center; gap: 0.125rem; margin-inline: -0.375rem auto; } /* 28px button, 16px chevron: drop btn-icon's padding so the icon isn't squeezed. */ .question-caret { padding: 0; } .question-caret[data-flip] [data-nucleo-icon] { rotate: 180deg; } .question-count { display: inline-flex; min-width: 0; gap: 0.375rem; padding-inline: 0.125rem; font-size: var(--text-sm); color: var(--color-text-tertiary); font-variant-numeric: tabular-nums; } .question-count strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; color: var(--color-text-primary); } /* * What focus looks like, once, for everything that can take it. An outline * rather than a ring: it follows `border-radius` and takes no space in the * layout. Components may still own their focused fill or other state; the * indicator's colour, width, and offset stay here. */ [data-focus-boundary] { --focus-ring-offset: -2px; } :where(a, button, input, select, summary, textarea, [role="button"], [tabindex]):focus-visible { outline: var(--focus-ring-width) solid var(--focus-ring-color); outline-offset: var(--focus-ring-offset); } /* MDXEditor paints task-list checkboxes on the focused list item's pseudo-element. */ .plan-content :is([class*="_listItemUnchecked"], [class*="_listItemChecked"]):focus-visible::before { outline: var(--focus-ring-width) solid var(--focus-ring-color); outline-offset: var(--focus-ring-offset); } /* * The ring answers "where am I?" for keyboard users, so it hides after a pointer * press. Text fields keep theirs: a caret alone is easy to lose. */ :root[data-focus-input="pointer"] :where(button, select, summary, [role="button"], [role="listbox"], [role="option"], [tabindex]:not(input, textarea)):focus-visible { outline: none; } /* The header title edits like a heading, not a form: beside its wash, a hairline is enough. */ :where(.document-title-input):focus-visible { outline-width: calc(var(--focus-ring-width) / 2); outline-offset: calc(var(--focus-ring-width) / -2); } /* A listbox holds the keyboard's place on its highlighted option instead. */ :where(.plan-language-menu[role="listbox"]):focus-visible { outline: none; } /* * A palette's search field is its header and always holds the caret, and its * highlighted row holds the keyboard's place, like a listbox option. */ :where(.navigation-palette-input, .navigation-palette-option):focus-visible { outline: none; } /* The editable plan has a live caret, so a second focus marker is redundant. */ :where(.focus-caret):focus-visible { outline: none; } .workspace-working-indicator { width: 0.875rem; height: 0.875rem; border: 2px solid currentColor; border-right-color: transparent; border-radius: var(--radius-full); } @media (prefers-reduced-motion: reduce) { .chat-work-lattice > span, .chat-work-headline-motion, .chat-source-tint { animation: none; } .btn[aria-busy="true"] [data-button-loader] { animation: none; } .motion-dropdown, .motion-popover, .motion-panel, .motion-content-swap, .motion-route-swap :is([data-workspace-document-swap], [data-chat-stack]), .motion-collapse, .motion-collapse-content { transition: none; } .workspace-root[data-workspace-mode="split"] .workspace-chat-panel[data-pane-moving] { transition: none; } :root[data-motion-input="pointer"] .chat-toggle-icon { transition: none; } [data-chat-enter] { transition: none; } .chat-header-control { transition: none; } :root[data-motion-input="pointer"] .motion-picker-option { transition: none; } :root[data-motion-input="pointer"] .motion-feedback[data-motion-feedback] { transition-duration: 0s; } } /* * What a press feels like. Zero specificity so a `transition` utility on the * element wins instead — Tailwind's covers `scale` along with the colours. * Disabled controls are excluded: a press that animates and then does nothing * says the opposite of what disabled is trying to say. */ :where(button, [role="button"]) { transition: scale var(--duration-fast) var(--ease-out); } /* * The scale is a proportion, so the default is subtle: 4% of a full-width row * is several pixels at each edge and reads as jumping, where 4% of a 28px * toolbar cell is the one pixel that is wanted. Small controls opt in to the * stronger press with `.btn-icon`, `.btn-sm`, or `data-press="small"`; a * full-screen backdrop opts out with `data-press="none"`. */ @media (prefers-reduced-motion: no-preference) { :where(button, [role="button"]):not(:disabled):active { scale: 0.99; } :where(button, [role="button"]):where(.btn-icon, .btn-sm, [data-press="small"]):not(:disabled):active { scale: 0.96; } :where(button, [role="button"])[data-press="none"]:not(:disabled):active { scale: none; } } .composer-surface:focus-within { outline: var(--edge-width) solid var(--color-brand); outline-offset: 0; } .composer-surface .composer-draft-input { outline: none; }