/* DocDoe Student OS — shared product surface polish */ .docdoe-student-os { --student-canvas: #ffffff; --student-panel: #ffffff; --student-ink: #171717; --student-ink-2: #404040; --student-muted: #666666; --student-muted-2: #707070; --student-line: #ebebeb; --student-line-strong: #c9c9c9; --student-accent: var(--student-ink); --student-accent-hover: #292929; --student-accent-soft: #f5f5f5; --student-rail: #fafafa; --student-scroll-thumb: #c9c9c9; --student-scroll-hover: #a3a3a3; --student-purple: var(--student-accent); --student-purple-hover: var(--student-accent-hover); --student-purple-soft: var(--student-accent-soft); --student-radius-sm: 8px; --student-radius-md: 12px; --student-radius-lg: 14px; --student-radius-xl: 18px; --student-shadow-sm: 0 1px 2px rgba(15, 17, 23, 0.03); --student-shadow-card: 0 1px 2px rgba(15, 17, 23, 0.03), 0 8px 24px rgba(15, 17, 23, 0.04); --student-shadow-lift: 0 2px 4px rgba(15, 17, 23, 0.04), 0 14px 32px rgba(15, 17, 23, 0.08); --student-ease: cubic-bezier(0.23, 1, 0.32, 1); --student-ease-out: cubic-bezier(0.16, 1, 0.3, 1); --student-motion-instant: 90ms; --student-motion-fast: 150ms; --student-motion-base: 200ms; --student-motion-slow: 260ms; --student-motion-settle: 320ms; --student-stagger-step: 40ms; --student-stagger-cap: 5; color-scheme: light; color: var(--student-ink); background: var(--student-canvas); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; --student-sidebar-w: 248px; --student-header-h: 56px; --student-bottom-nav-h: 64px; --student-safe-bottom: env(safe-area-inset-bottom, 0px); --student-safe-top: env(safe-area-inset-top, 0px); --student-shell-bottom: calc( var(--student-bottom-nav-h) + var(--student-safe-bottom) ); overflow-x: clip; max-width: 100%; } @media (min-width: 1024px) { .docdoe-student-os { --student-header-h: 68px; --student-shell-bottom: 0px; } } .docdoe-student-os ::selection { background: rgba(23, 23, 22, 0.14); } .docdoe-student-os :is(h1, h2) { text-wrap: balance; } .docdoe-student-os :is(p, li, figcaption) { text-wrap: pretty; } .docdoe-student-os, .docdoe-student-os * { scrollbar-color: var(--student-scroll-thumb) transparent; scrollbar-width: thin; } .docdoe-student-os ::-webkit-scrollbar { width: 7px; height: 7px; } .docdoe-student-os ::-webkit-scrollbar-thumb { border: 2px solid transparent; border-radius: 999px; background: var(--student-scroll-thumb); background-clip: padding-box; } .docdoe-student-os ::-webkit-scrollbar-thumb:hover { background: var(--student-scroll-hover); background-clip: padding-box; } @media (forced-colors: active) { .docdoe-student-os, .docdoe-student-os * { scrollbar-color: auto; scrollbar-width: auto; } .docdoe-student-os ::-webkit-scrollbar-thumb { background: ButtonText; } } .docdoe-student-os button, .docdoe-student-os a { -webkit-tap-highlight-color: transparent; } .docdoe-student-os button:not(:disabled), .docdoe-student-os a[href] { cursor: pointer; } .docdoe-student-os :is(h1, h2, h3, [tabindex="-1"]) { scroll-margin-top: calc(var(--student-header-h) + 16px); } /* Migrate repeated legacy utility colors through the shared product tokens so muted labels remain readable without changing every page-local component. */ .docdoe-student-os [class~="text-[#73757c]"] { color: var(--student-muted) !important; } .docdoe-student-os [class~="text-[#92949a]"] { color: var(--student-muted-2) !important; } /* A few older Student OS surfaces still carry pale metadata utilities. Route them through the same readable muted token instead of maintaining a second contrast scale in individual pages. */ .docdoe-student-os [class~="text-[#6f7484]"], .docdoe-student-os [class~="text-[#747783]"], .docdoe-student-os [class~="text-[#7a8190]"], .docdoe-student-os [class~="text-[#83848d]"], .docdoe-student-os [class~="text-[#858690]"], .docdoe-student-os [class~="text-[#858894]"], .docdoe-student-os [class~="text-[#888993]"], .docdoe-student-os [class~="text-[#898a94]"], .docdoe-student-os [class~="text-[#898b95]"], .docdoe-student-os [class~="text-[#8a8b94]"], .docdoe-student-os [class~="text-[#8b8c95]"], .docdoe-student-os [class~="text-[#a8aaaf]"] { color: var(--student-muted) !important; } .docdoe-student-os [class~="text-white/30"], .docdoe-student-os [class~="text-white/40"], .docdoe-student-os [class~="text-white/45"] { color: rgb(255 255 255 / 0.68) !important; } /* Shared card elevation */ .docdoe-student-os .student-panel { border: 1px solid var(--student-line); border-radius: var(--student-radius-lg); background: var(--student-panel); box-shadow: var(--student-shadow-card); } .docdoe-student-os .student-card-lift { transition: transform 170ms var(--student-ease), border-color 170ms var(--student-ease), box-shadow 170ms var(--student-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .student-card-lift:hover { transform: translateY(-2px); border-color: var(--student-line-strong); box-shadow: var(--student-shadow-lift); } } .docdoe-student-os .student-card-lift:active { transform: translateY(0) scale(0.995); } /* Pressable controls */ .docdoe-student-os .student-press { transition: transform 140ms var(--student-ease), background-color 160ms var(--student-ease), border-color 160ms var(--student-ease), box-shadow 160ms var(--student-ease), color 160ms var(--student-ease); } .docdoe-student-os .student-press:active:not(:disabled) { transform: scale(0.97); } .docdoe-student-os .student-press:focus-visible { outline: 2px solid var(--student-accent); outline-offset: 2px; } /* Quiet eyebrow labels — product, not marketing shout */ .docdoe-student-os .student-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--student-muted); } .docdoe-student-os .student-eyebrow-accent { font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--student-purple); } /* Input focus ring */ .docdoe-student-os .student-input-ring { transition: border-color 160ms var(--student-ease), box-shadow 160ms var(--student-ease); } .docdoe-student-os .student-input-ring:focus-within { border-color: rgba(23, 24, 27, 0.45); box-shadow: 0 0 0 3px rgba(23, 24, 27, 0.1); } /* Page-local classes predate the Student OS tokens. Keep those routes visually coherent while they are migrated: purple is not a product accent. */ .docdoe-student-os [class~="text-[#6c43f3]"], .docdoe-student-os [class~="text-[#6d5ce7]"], .docdoe-student-os [class~="text-[#5b35e0]"], .docdoe-student-os [class~="text-[#5a49d6]"], .docdoe-student-os [class~="text-[#7b5bf0]"], .docdoe-student-os [class~="text-[#7865e7]"], .docdoe-student-os [class*="text-violet-"] { color: var(--student-accent) !important; } .docdoe-student-os [class~="bg-[#6c43f3]"], .docdoe-student-os [class~="bg-[#6d5ce7]"], .docdoe-student-os [class*="bg-violet-"] { background-color: var(--student-accent) !important; background-image: none !important; } .docdoe-student-os [class~="bg-[#f1edff]"], .docdoe-student-os [class~="bg-[#f1ebff]"], .docdoe-student-os [class~="bg-[#f0edff]"], .docdoe-student-os [class~="bg-[#f2efff]"], .docdoe-student-os [class~="bg-[#f7f5ff]"], .docdoe-student-os [class*="bg-violet-50"] { background-color: var(--student-accent-soft) !important; background-image: none !important; } .docdoe-student-os [class*="border-violet-"] { border-color: var(--student-line-strong) !important; } .docdoe-student-os [class*="from-[#f1edff]"], .docdoe-student-os [class*="from-[#f4edff]"], .docdoe-student-os [class*="to-[#fbfaff]"] { --tw-gradient-from: var(--student-accent-soft) !important; --tw-gradient-to: var(--student-panel) !important; } .docdoe-student-os :is(a, button, input, select, textarea):focus-visible { outline: 2px solid var(--student-accent); outline-offset: 2px; } /* The light rail and drawer need the same graphite keyboard cue as content. */ .docdoe-student-os aside :is(a, button):focus-visible { outline-color: var(--student-ink); outline-width: 3px; } .docdoe-student-os .student-os-sheet :is(a, button), .docdoe-student-os [data-testid="docdoe-page-guide"] :is(a, button), .docdoe-student-os [role="dialog"] :is(a, button) { min-height: 44px; } @media (max-width: 639px) { .docdoe-student-os main.student-os-main { padding-inline: 0; } } /* Shared mobile chrome helpers */ .docdoe-student-os .student-os-main { min-height: calc(100dvh - var(--student-header-h)); padding-bottom: calc(var(--student-shell-bottom) + 12px); outline: none; } @media (min-width: 1024px) { .docdoe-student-os .student-os-main { padding-bottom: 5.5rem; } } .docdoe-student-os .student-route-surface { min-height: inherit; } .docdoe-student-os .student-os-header { min-height: calc(var(--student-header-h) + var(--student-safe-top)); padding-top: var(--student-safe-top); } .docdoe-student-os .student-os-bottom-nav { height: calc(var(--student-bottom-nav-h) + var(--student-safe-bottom)); padding-bottom: var(--student-safe-bottom); } @keyframes docdoe-mascot-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } } .docdoe-mascot-bob { animation: docdoe-mascot-bob 2.8s ease-in-out infinite; } @media (prefers-reduced-motion: reduce) { .docdoe-mascot-bob { animation: none; } } /* Prevent iOS input zoom without fighting desktop scale */ @media (max-width: 767px) { .docdoe-student-os input, .docdoe-student-os select, .docdoe-student-os textarea { font-size: 16px !important; } } /* Full-bleed fixed sheets above bottom nav + helper FAB */ .docdoe-student-os .student-os-sheet { z-index: 80; } /* Horizontal safety for long content rows */ .docdoe-student-os .student-os-main, .docdoe-student-os .student-os-main > * { max-width: 100%; } .docdoe-student-os .student-loading-block { overflow: hidden; border-radius: 6px; background: #ebeae5; background-image: linear-gradient( 100deg, transparent 20%, rgba(255, 255, 255, 0.82) 40%, transparent 60% ); background-position: 120% 0; background-size: 220% 100%; animation: student-loading-sheen 1.6s ease-in-out infinite; } .docdoe-student-os .student-loading-line { animation: student-loading-line 1.35s var(--student-ease-out) infinite; transform-origin: left center; } @keyframes student-loading-sheen { 0% { background-position: 120% 0; } 100% { background-position: -120% 0; } } @keyframes student-loading-line { 0% { transform: translateX(-110%) scaleX(0.45); } 55% { transform: translateX(130%) scaleX(0.9); } 100% { transform: translateX(320%) scaleX(0.45); } } @media (prefers-reduced-motion: reduce) { .docdoe-student-os *, .docdoe-student-os *::before, .docdoe-student-os *::after { scroll-behavior: auto !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } .docdoe-student-os .student-card-lift:hover, .docdoe-student-os .student-card-lift:active, .docdoe-student-os .student-press:active:not(:disabled) { transform: none; } .docdoe-student-os .student-loading-block { animation: none !important; opacity: 0.7; } .docdoe-student-os .student-loading-line { width: 40%; animation: none !important; opacity: 0.7; transform: none; } } @keyframes docdoe-thinking-pulse { 0%, 70%, 100% { opacity: 0.28; transform: translateY(0); } 35% { opacity: 1; transform: translateY(-1.5px); } } @keyframes tuition-load-sweep { 0% { transform: translateX(-120%); } 100% { transform: translateX(360%); } } @keyframes la-plan-load-sweep { 0% { transform: translateX(-120%); } 100% { transform: translateX(360%); } } @keyframes la-plan-card-rise { 0% { opacity: 0.35; transform: translateY(6px); } 100% { opacity: 1; transform: translateY(0); } } @keyframes la-plan-pulse { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } } .la-plan-load-bar { animation: la-plan-load-sweep 1.15s cubic-bezier(0.4, 0, 0.2, 1) infinite; will-change: transform; } .la-plan-card-rise { animation: la-plan-card-rise 0.55s cubic-bezier(0.16, 1, 0.3, 1) both; } .la-plan-pulse { animation: la-plan-pulse 1.1s ease-in-out infinite; } /* Quiet indeterminate bar for tuition class prep */ .tuition-load-bar { animation: tuition-load-sweep 1.15s cubic-bezier(0.4, 0, 0.2, 1) infinite; will-change: transform; } .docdoe-thinking-dots { display: inline-flex; gap: 3px; } .docdoe-thinking-dots i { width: 4px; height: 4px; border-radius: 999px; background: currentColor; animation: docdoe-thinking-pulse 1.05s ease-in-out infinite; } .docdoe-thinking-dots i:nth-child(2) { animation-delay: 0.13s; } .docdoe-thinking-dots i:nth-child(3) { animation-delay: 0.26s; } /* Shared muted labels must remain readable on the app and auth surfaces. */ [class~="text-[#777873]"], [class~="text-[#73757c]"], [class~="text-[#92949a]"], [class~="text-[#898a85]"] { color: #5c6170 !important; } /* Learn Anything uses lighter editorial metadata tokens on a white surface. */ [class~="text-[#9CA3AF]"], [class~="text-[#C4C4CC]"] { color: #62635e !important; } /* ------------------------------------------------------------------ * * Entrance choreography * * Deliberately CSS-only: the stagger, card rise and progress fill run on the * compositor with no JavaScript per node, which matters on low-end Android * where a 40-item grid animated through JS springs drops frames. Only * transform and opacity are touched. * ------------------------------------------------------------------ */ @keyframes student-rise { from { opacity: 0; transform: translate3d(0, 10px, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } } @keyframes student-fade { from { opacity: 0; } to { opacity: 1; } } /* Staggered children, capped at 6: delay = min(i, 5) * 40ms, so the whole group settles within 200ms. The 7th sibling onward renders static — a 40-row grid must never animate 40 nodes, they arrive with the container instead. */ .docdoe-student-os .student-stagger { animation: student-fade var(--student-motion-slow) var(--student-ease-out) both; } .docdoe-student-os .student-stagger > * { animation: student-rise 220ms var(--student-ease-out) both; } .docdoe-student-os .student-stagger > *:nth-child(1) { animation-delay: 0ms; } .docdoe-student-os .student-stagger > *:nth-child(2) { animation-delay: 40ms; } .docdoe-student-os .student-stagger > *:nth-child(3) { animation-delay: 80ms; } .docdoe-student-os .student-stagger > *:nth-child(4) { animation-delay: 120ms; } .docdoe-student-os .student-stagger > *:nth-child(5) { animation-delay: 160ms; } .docdoe-student-os .student-stagger > *:nth-child(6) { animation-delay: 200ms; } /* Beyond the cap the children stop animating individually and ride the container's single fade. This is what keeps long lists cheap. */ .docdoe-student-os .student-stagger > *:nth-child(n + 7) { animation: none; } /* Slower variant for page-level sections, which read as larger blocks. */ .docdoe-student-os .student-stagger-slow > * { animation-duration: var(--student-motion-slow); } .docdoe-student-os .student-stagger-fade > * { animation-name: student-fade; } /* Standalone rising element. */ .docdoe-student-os .student-rise { animation: student-rise var(--student-motion-slow) var(--student-ease-out) both; } .docdoe-student-os .student-fade-in { animation: student-fade var(--student-motion-base) var(--student-ease-out) both; } /* Progress fills animate with scaleX (compositor) instead of width (layout), which is the difference between smooth and janky on a weak GPU. */ .docdoe-student-os .student-progress-track { position: relative; overflow: hidden; border-radius: 999px; background: #e6e7e2; } .docdoe-student-os .student-progress-fill { display: block; height: 100%; width: 100%; border-radius: inherit; background: var(--student-accent); transform-origin: left center; transform: scaleX(var(--student-progress, 0)); transition: transform var(--student-motion-settle) var(--student-ease-out); } /* ------------------------------------------------------------------ * * Tuition focus mode * * The tuition surfaces are deliberately dark — it is an intentional * concentration mode, not an oversight, so it must NOT be "fixed" to match the * light canvas. It was, however, ~345 hardcoded hex literals spread across 12 * files with no single source of truth. These tokens are that source: new work * should reference them, and the legacy literals migrate over time. * ------------------------------------------------------------------ */ .docdoe-tuition-focus { --tuition-canvas: #0d0d0d; --tuition-surface: #111111; --tuition-surface-raised: #1a1a1a; --tuition-border: #2a2a2a; --tuition-border-strong: #333333; --tuition-ink: #ffffff; --tuition-muted: #8b8b8b; --tuition-success: #10b981; --tuition-critical: #ef4444; --tuition-track: rgb(255 255 255 / 0.12); } /* Tuition runs on the dark focus surface, so the track tint differs but the fill still animates with scaleX for the same compositor reason. */ .tuition-progress-fill { transform-origin: left center; transform: scaleX(var(--tuition-progress, 0)); transition: transform var(--student-motion-settle) var(--student-ease-out); } /* Subtle sheen that runs once when a panel mounts — signals "fresh content" without a spinner. */ @keyframes student-panel-settle { from { opacity: 0; transform: translate3d(0, 6px, 0) scale(0.995); } to { opacity: 1; transform: translate3d(0, 0, 0) scale(1); } } .docdoe-student-os .student-panel-settle { animation: student-panel-settle var(--student-motion-settle) var(--student-ease-out) both; } /* Count-up values should not reflow their neighbours as digits change. */ .docdoe-student-os .student-tabular { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; } @media (prefers-reduced-motion: reduce) { .tuition-load-bar, .la-plan-load-bar, .la-plan-card-rise, .la-plan-pulse, .docdoe-thinking-dots i { animation: none; } .tuition-load-bar, .la-plan-load-bar { width: 40%; opacity: 0.75; } .docdoe-student-os .student-stagger > *, .docdoe-student-os .student-rise, .docdoe-student-os .student-fade-in, .docdoe-student-os .student-panel-settle { animation: none !important; opacity: 1 !important; transform: none !important; } .docdoe-student-os .student-progress-fill { transition: none; } } /* ------------------------------------------------------------------ * * DocDoe craft layer — shared language for /home, /tuition, /study-chat * * Three routes were rewritten against one vocabulary instead of three local * dialects. The rules that keep it coherent: * * - White content and a quiet gray rail. Group through space and typography; * reserve subtle surfaces for related work, not stacks of promotional cards. * - One neutral scale, owned by --student-* and exposed through --dd-*. * No independent warm or blue-gray palette in individual student routes. * - Hue is status. Green/amber/red carry evidence, revision and failure. * They are never decoration, so at most one appears per reading band. * - Motion is 150-250ms ease-out and only ever answers a user action: * hover, focus, press, and value changes. Nothing animates on its own. * ------------------------------------------------------------------ */ .docdoe-student-os { --dd-paper: var(--student-canvas); --dd-canvas: var(--student-rail); --dd-sunk: var(--student-accent-soft); --dd-panel: var(--student-panel); --dd-ink: var(--student-ink); --dd-ink-2: var(--student-ink-2); --dd-muted: var(--student-muted); --dd-faint: var(--student-muted-2); --dd-line: var(--student-line); --dd-line-strong: var(--student-line-strong); --dd-positive: #147a5a; --dd-positive-soft: #eaf4ef; --dd-positive-line: #cfe4d9; --dd-attention: #a66b1f; --dd-attention-soft: #fbf3e7; --dd-attention-line: #eddcbe; --dd-critical: #b33a3a; --dd-critical-soft: #fbedec; --dd-critical-line: #eed3d1; /* Board world. Only class/board surfaces may use these, and only the chalk hairline below may carry a hue inside them. */ --dd-board: #0b0f0e; --dd-board-panel: #0e1413; --dd-board-line: #232a28; --dd-board-ink: #f2f4f1; --dd-board-muted: #8f9a92; --dd-chalk: #ead08c; --dd-r-sm: 8px; --dd-r-md: 10px; --dd-r-lg: 14px; --dd-r-xl: 18px; --dd-ease: cubic-bezier(0.16, 1, 0.3, 1); --dd-ease-soft: cubic-bezier(0.23, 1, 0.32, 1); --dd-t-fast: 150ms; --dd-t-base: 200ms; --dd-t-slow: 250ms; --dd-t-settle: 320ms; } /* ── Typography atoms ─────────────────────────────────────────────── */ /* 11px tracked caps. The product voice for structure; never a headline. */ .docdoe-student-os .dd-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.09em; line-height: 1; text-transform: uppercase; color: var(--dd-faint); } .docdoe-student-os .dd-eyebrow-ink { color: var(--dd-ink-2); } /* Docket numerals: index numbers, counts, and any figure that must not reflow while its neighbours change. */ .docdoe-student-os .dd-mono { font-family: var(--font-mono), ui-monospace, monospace; font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; letter-spacing: 0.02em; } /* Display figures — the hero moment's numbers only. */ .docdoe-student-os .dd-figure { font-family: var(--font-display), var(--font-sans), sans-serif; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -0.03em; line-height: 0.95; } /* ── Structure: rules and tear-lines ──────────────────────────────── */ .docdoe-student-os .dd-rule { height: 1px; background: var(--dd-line); border: 0; } .docdoe-student-os .dd-tear { height: 0; border: 0; border-top: 1px dashed var(--dd-line-strong); } .docdoe-student-os .dd-rule-vertical { width: 1px; align-self: stretch; background: var(--dd-line); } /* ── Press and focus ──────────────────────────────────────────────── */ .docdoe-student-os .dd-press { transition: transform var(--dd-t-fast) var(--dd-ease), background-color var(--dd-t-base) var(--dd-ease), border-color var(--dd-t-base) var(--dd-ease), color var(--dd-t-base) var(--dd-ease), box-shadow var(--dd-t-base) var(--dd-ease); } .docdoe-student-os .dd-press:active:not(:disabled) { transform: scale(0.975); } .docdoe-student-os .dd-press:focus-visible, .docdoe-student-os .dd-focusable:focus-visible { outline: 2px solid var(--dd-ink); outline-offset: 2px; } /* ── Marks ────────────────────────────────────────────────────────── */ /* The product mark. A hairline inset gives the flat ink tile a physical edge without a glow or gradient. */ .docdoe-student-os .dd-mark { display: grid; place-items: center; border-radius: var(--dd-r-md); background: var(--dd-ink); color: #fff; box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.14); transition: transform var(--dd-t-base) var(--dd-ease); } .docdoe-student-os .dd-mark-quiet { background: var(--dd-sunk); color: var(--dd-ink); box-shadow: inset 0 0 0 1px rgb(23 23 22 / 0.05); } /* ── Buttons ──────────────────────────────────────────────────────── */ .docdoe-student-os .dd-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; border-radius: var(--dd-r-md); font-size: 14px; font-weight: 600; letter-spacing: -0.005em; white-space: nowrap; } .docdoe-student-os .dd-btn-ink { background: var(--dd-ink); color: #fff; box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.1); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-btn-ink:hover:not(:disabled) { background: #2b2b29; } } .docdoe-student-os .dd-btn-ink:disabled { background: #cfcfca; color: #fbfbfa; box-shadow: none; } .docdoe-student-os .dd-btn-paper { background: var(--dd-panel); border: 1px solid var(--dd-line-strong); color: var(--dd-ink); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-btn-paper:hover:not(:disabled) { border-color: #b9b8b1; background: var(--dd-paper); } } .docdoe-student-os .dd-btn-ghost { background: transparent; color: var(--dd-ink-2); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-btn-ghost:hover:not(:disabled) { background: var(--dd-sunk); color: var(--dd-ink); } } /* The inverse button belongs to the board world: white fill, ink text. */ .docdoe-student-os .dd-btn-board { background: var(--dd-board-ink); color: var(--dd-board); box-shadow: inset 0 0 0 1px rgb(11 15 14 / 0.12); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-btn-board:hover:not(:disabled) { background: #fff; } } /* Arrow that answers a hover without moving the layout. */ .docdoe-student-os .dd-arrow { transition: transform var(--dd-t-base) var(--dd-ease); } .docdoe-student-os .group:hover .dd-arrow, .docdoe-student-os .group:focus-visible .dd-arrow { transform: translateX(3px); } /* Quiet link: the underline draws from the left on hover instead of a colour flash, so it reads as navigation rather than a state change. */ .docdoe-student-os .dd-link { position: relative; display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--dd-ink-2); } .docdoe-student-os .dd-link::after { content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: left center; transition: transform var(--dd-t-base) var(--dd-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-link:hover::after { transform: scaleX(1); } } .docdoe-student-os .dd-link:focus-visible::after { transform: scaleX(1); } /* ── Rows ─────────────────────────────────────────────────────────── */ /* Rows replace cards for anything that repeats. The hover is a surface tint plus an arrow nudge — no lift, no shadow, no nested border. */ .docdoe-student-os .dd-row { position: relative; display: flex; align-items: center; gap: 12px; transition: background-color var(--dd-t-fast) var(--dd-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-row-interactive:hover { background: var(--dd-paper); } } /* ── Meter ────────────────────────────────────────────────────────── */ /* Fills animate with scaleX so the value change never triggers layout. */ .docdoe-student-os .dd-meter { position: relative; height: 3px; width: 100%; overflow: hidden; border-radius: 999px; background: var(--dd-line); } .docdoe-student-os .dd-meter > i { position: absolute; inset: 0; display: block; border-radius: inherit; background: var(--dd-ink); transform-origin: left center; transform: scaleX(var(--dd-value, 0)); transition: transform var(--dd-t-settle) var(--dd-ease); } /* ── Chips ────────────────────────────────────────────────────────── */ .docdoe-student-os .dd-chip { display: inline-flex; align-items: center; gap: 6px; border-radius: 999px; padding: 4px 9px; font-size: 11px; font-weight: 600; letter-spacing: 0.02em; line-height: 1; white-space: nowrap; } .docdoe-student-os .dd-chip-ink { background: var(--dd-ink); color: #fff; } .docdoe-student-os .dd-chip-quiet { background: var(--dd-sunk); color: var(--dd-ink-2); } .docdoe-student-os .dd-chip-outline { border: 1px solid var(--dd-line-strong); color: var(--dd-ink-2); } /* ── Completion tick ──────────────────────────────────────────────── */ /* The ring draws itself when a task is completed. It is the only place a stroke animation appears, because it is the one state change a student performs deliberately and wants confirmed. */ .docdoe-student-os .dd-tick { display: grid; place-items: center; border-radius: 999px; border: 1.5px solid var(--dd-line-strong); color: transparent; transition: border-color var(--dd-t-base) var(--dd-ease), background-color var(--dd-t-base) var(--dd-ease), color var(--dd-t-base) var(--dd-ease), transform var(--dd-t-fast) var(--dd-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os button:hover > .dd-tick, .docdoe-student-os .dd-tick-host:hover .dd-tick { border-color: var(--dd-positive); transform: scale(1.06); } } .docdoe-student-os .dd-tick-done { border-color: var(--dd-positive); background: var(--dd-positive); color: #fff; } @keyframes dd-tick-pop { 0% { transform: scale(0.82); } 60% { transform: scale(1.08); } 100% { transform: scale(1); } } .docdoe-student-os .dd-tick-just-done { animation: dd-tick-pop 240ms var(--dd-ease); } /* ── Fields ───────────────────────────────────────────────────────── */ .docdoe-student-os .dd-field { border-radius: var(--dd-r-lg); border: 1px solid var(--dd-line-strong); background: var(--dd-panel); transition: border-color var(--dd-t-base) var(--dd-ease), box-shadow var(--dd-t-base) var(--dd-ease); } .docdoe-student-os .dd-field:focus-within { border-color: rgb(23 23 22 / 0.42); box-shadow: 0 0 0 3px rgb(23 23 22 / 0.07); } /* ── Board surface ────────────────────────────────────────────────── */ /* The one dark surface in the product. It is a blackboard, so it gets a chalk hairline and a vignette rather than a card shadow, and the chalk hue is confined to rules inside this element. */ .docdoe-student-os .dd-board { position: relative; overflow: hidden; background: var(--dd-board); color: var(--dd-board-ink); border-radius: var(--dd-r-lg); } .docdoe-student-os .dd-board::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: radial-gradient( 120% 90% at 88% 6%, rgb(234 208 140 / 0.07), transparent 62% ); } .docdoe-student-os .dd-chalk-rule { height: 1px; border: 0; background: linear-gradient( 90deg, rgb(234 208 140 / 0.5), rgb(234 208 140 / 0.1) 55%, transparent ); } /* ── Reduced motion ───────────────────────────────────────────────── */ /* ── Route reveal ────────────────────────────────────────────────── */ /* One entrance per route, never per card and never scroll-triggered: the page arrives as a single block so a student re-entering a tab is not waiting on a cascade. Everything below it is state-transition motion. */ @keyframes dd-page-in { from { opacity: 0; transform: translate3d(0, 7px, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } } .docdoe-student-os .dd-page-in { animation: dd-page-in var(--dd-t-slow) var(--dd-ease) both; } /* A conversation entry is the one repeat element allowed to animate in: each message is a discrete arrival, not decoration. */ @keyframes dd-entry-in { from { opacity: 0; transform: translate3d(0, 9px, 0); } to { opacity: 1; transform: translate3d(0, 0, 0); } } .docdoe-student-os .dd-entry { animation: dd-entry-in 240ms var(--dd-ease) both; } /* ── Status blocks ───────────────────────────────────────────────── */ /* Hue is evidence, never decoration. Each block states one fact about the student's work, so at most one appears per reading band. */ .docdoe-student-os .dd-status { display: flex; align-items: flex-start; gap: 10px; border-radius: var(--dd-r-md); border: 1px solid; padding: 11px 13px; font-size: 13px; line-height: 20px; } .docdoe-student-os .dd-status > svg { margin-top: 3px; flex-shrink: 0; } .docdoe-student-os .dd-status-positive { border-color: var(--dd-positive-line); background: var(--dd-positive-soft); color: var(--dd-positive); } .docdoe-student-os .dd-status-attention { border-color: var(--dd-attention-line); background: var(--dd-attention-soft); color: var(--dd-attention); } .docdoe-student-os .dd-status-critical { border-color: var(--dd-critical-line); background: var(--dd-critical-soft); color: var(--dd-critical); } /* ── Quiet icon button ───────────────────────────────────────────── */ /* Chrome controls sit at the edge of the reading band. They gain a surface on hover rather than a colour change, so they stay furniture. */ .docdoe-student-os .dd-icon-btn { display: grid; place-items: center; border-radius: var(--dd-r-md); color: var(--dd-muted); transition: background-color var(--dd-t-fast) var(--dd-ease), color var(--dd-t-fast) var(--dd-ease), transform var(--dd-t-fast) var(--dd-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-icon-btn:hover:not(:disabled) { background: var(--dd-sunk); color: var(--dd-ink); } } .docdoe-student-os .dd-icon-btn:active:not(:disabled) { transform: scale(0.94); } .docdoe-student-os .dd-icon-btn:disabled { opacity: 0.4; } /* ── Rails ───────────────────────────────────────────────────────── */ /* Side rails are ruled lists on the sunken canvas — never a stack of cards, because a rail is navigation and cards imply content. */ .docdoe-student-os .dd-rail { display: flex; min-height: 0; flex-direction: column; } .docdoe-student-os .dd-rail-head { padding: 16px 16px 12px; } .docdoe-student-os .dd-rail-scroll { min-height: 0; flex: 1; overflow-y: auto; padding: 4px 8px; } .docdoe-student-os .dd-rail-item { display: flex; width: 100%; align-items: flex-start; gap: 10px; border-radius: var(--dd-r-md); padding: 9px 10px; text-align: left; transition: background-color var(--dd-t-fast) var(--dd-ease), color var(--dd-t-fast) var(--dd-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-rail-item:hover:not([data-active="true"]) { background: var(--dd-panel); } } .docdoe-student-os .dd-rail-item[data-active="true"] { background: var(--dd-ink); color: #fff; box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.1); } /* ── Conversation ────────────────────────────────────────────────── */ /* The student's own message is the only inverted block in the thread. The asymmetric corner is the tail: it points at the sender without an avatar bubble competing with the assistant's mark. */ .docdoe-student-os .dd-bubble-user { border-radius: 16px 16px 4px 16px; background: var(--dd-ink); color: #fff; padding: 11px 15px; font-size: 14px; line-height: 24px; box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.08); } /* Assistant sections are ruled, not boxed: a multi-part answer reads as one continuous document with an index in the margin. */ .docdoe-student-os .dd-answer-section { border-top: 1px solid var(--dd-line); padding: 16px 0; } .docdoe-student-os .dd-answer-section:last-of-type { border-bottom: 1px solid var(--dd-line); } /* ── Prose ───────────────────────────────────────────────────────── */ /* Tutor output is markdown, so the reading measure and rhythm are set here rather than per call site. Without this every answer re-invents spacing. */ .docdoe-student-os .dd-prose { font-size: 14.5px; line-height: 26px; color: var(--dd-ink-2); } .docdoe-student-os .dd-prose > :first-child { margin-top: 0; } .docdoe-student-os .dd-prose > :last-child { margin-bottom: 0; } .docdoe-student-os .dd-prose p { margin-block: 0 12px; } .docdoe-student-os .dd-prose strong { font-weight: 600; color: var(--dd-ink); } .docdoe-student-os .dd-prose h1, .docdoe-student-os .dd-prose h2, .docdoe-student-os .dd-prose h3, .docdoe-student-os .dd-prose h4 { margin-block: 18px 8px; font-weight: 600; letter-spacing: -0.022em; color: var(--dd-ink); } .docdoe-student-os .dd-prose h3 { font-size: 15px; } .docdoe-student-os .dd-prose ul, .docdoe-student-os .dd-prose ol { margin-block: 12px; padding-left: 20px; } .docdoe-student-os .dd-prose ul { list-style: disc; } .docdoe-student-os .dd-prose ol { list-style: decimal; } .docdoe-student-os .dd-prose li { margin-block: 5px; } .docdoe-student-os .dd-prose li::marker { color: var(--dd-faint); } .docdoe-student-os .dd-prose code { border-radius: 4px; background: var(--dd-sunk); padding: 1px 5px; font-family: var(--font-mono), ui-monospace, monospace; font-size: 0.9em; } .docdoe-student-os .dd-prose pre { margin-block: 14px; overflow-x: auto; border-radius: var(--dd-r-md); background: var(--dd-sunk); padding: 12px 14px; } .docdoe-student-os .dd-prose pre code { background: none; padding: 0; } .docdoe-student-os .dd-prose blockquote { margin-block: 14px; border-left: 2px solid var(--dd-line-strong); padding-left: 14px; color: var(--dd-muted); } .docdoe-student-os .dd-prose a { color: var(--dd-ink); text-decoration: underline; text-decoration-color: var(--dd-line-strong); text-underline-offset: 3px; transition: text-decoration-color var(--dd-t-fast) var(--dd-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-prose a:hover { text-decoration-color: var(--dd-ink); } } .docdoe-student-os .dd-prose table { margin-block: 14px; width: 100%; border-collapse: collapse; font-size: 13.5px; } .docdoe-student-os .dd-prose th, .docdoe-student-os .dd-prose td { border-bottom: 1px solid var(--dd-line); padding: 7px 10px; text-align: left; } .docdoe-student-os .dd-prose th { font-weight: 600; color: var(--dd-ink); } .docdoe-student-os .dd-prose hr { margin-block: 18px; border: 0; border-top: 1px solid var(--dd-line); } /* ── Small actions ───────────────────────────────────────────────── */ /* Secondary actions under an answer. Outlined and quiet so the primary reading path stays the answer itself. */ .docdoe-student-os .dd-action { display: inline-flex; height: 32px; align-items: center; gap: 6px; border-radius: var(--dd-r-sm); border: 1px solid var(--dd-line); background: transparent; padding-inline: 10px; font-size: 12px; font-weight: 500; color: var(--dd-muted); white-space: nowrap; transition: background-color var(--dd-t-fast) var(--dd-ease), border-color var(--dd-t-fast) var(--dd-ease), color var(--dd-t-fast) var(--dd-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-action:hover:not(:disabled) { background: var(--dd-sunk); border-color: var(--dd-line-strong); color: var(--dd-ink); } } .docdoe-student-os .dd-action:disabled { opacity: 0.45; cursor: not-allowed; } /* ── Removable chip ──────────────────────────────────────────────── */ .docdoe-student-os .dd-chip-remove { display: inline-flex; max-width: 220px; align-items: center; gap: 6px; border-radius: var(--dd-r-sm); background: var(--dd-sunk); padding: 5px 8px; font-size: 12px; font-weight: 500; color: var(--dd-ink-2); transition: background-color var(--dd-t-fast) var(--dd-ease), color var(--dd-t-fast) var(--dd-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-chip-remove:hover { background: var(--dd-ink); color: #fff; } } .docdoe-student-os .dd-chip-remove > svg { flex-shrink: 0; opacity: 0.55; transition: opacity var(--dd-t-fast) var(--dd-ease); } .docdoe-student-os .dd-chip-remove:hover > svg { opacity: 1; } /* ── Citation ────────────────────────────────────────────────────── */ /* Evidence rows. They must look like a source, not a button: a hairline border that only strengthens on intent. */ .docdoe-student-os .dd-cite { display: block; border-radius: var(--dd-r-md); border: 1px solid var(--dd-line); background: var(--dd-panel); padding: 10px 12px; transition: border-color var(--dd-t-fast) var(--dd-ease), background-color var(--dd-t-fast) var(--dd-ease); } @media (hover: hover) and (pointer: fine) { .docdoe-student-os .dd-cite:hover { border-color: var(--dd-line-strong); background: var(--dd-paper); } } /* ── Route stepper ───────────────────────────────────────────────── */ /* A class is a sequence, so the steps get a real spine: one hairline connecting the nodes rather than 5 identical boxed rows. */ .docdoe-student-os .dd-stepper { position: relative; } .docdoe-student-os .dd-step { position: relative; display: flex; align-items: flex-start; gap: 12px; padding-block: 13px; } .docdoe-student-os .dd-step + .dd-step { border-top: 1px solid var(--dd-line); } .docdoe-student-os .dd-step-node { display: grid; place-items: center; flex-shrink: 0; border-radius: 999px; border: 1px solid var(--dd-line-strong); background: var(--dd-panel); color: var(--dd-faint); transition: background-color var(--dd-t-base) var(--dd-ease), border-color var(--dd-t-base) var(--dd-ease), color var(--dd-t-base) var(--dd-ease); } .docdoe-student-os .dd-step[data-current="true"] .dd-step-node { border-color: var(--dd-ink); background: var(--dd-ink); color: #fff; } /* ── Hero spine ──────────────────────────────────────────────────── */ /* The day's hero earns one piece of structure the rest of the page does not get: an ink edge that marks it as the first thing to read. */ .docdoe-student-os .dd-spine { position: relative; } .docdoe-student-os .dd-spine::before { content: ""; position: absolute; inset-block: 0; left: 0; width: 3px; background: var(--dd-ink); } /* ── Board-detail strip ──────────────────────────────────────────── */ /* Hairline metadata strip on the inverted hero. Uses paper translucency, never a chalk hue — chalk is reserved for actual board surfaces. */ .docdoe-student-os .dd-ink-rule { height: 1px; border: 0; background: linear-gradient( 90deg, rgb(255 255 255 / 0.22), rgb(255 255 255 / 0.05) 60%, transparent ); } @media (prefers-reduced-motion: reduce) { .docdoe-student-os .dd-tick-just-done, .docdoe-student-os .dd-arrow, .docdoe-student-os .dd-mark, .docdoe-student-os .dd-page-in, .docdoe-student-os .dd-entry { animation: none; transform: none; } .docdoe-student-os .dd-meter > i { transition: none; } .docdoe-student-os .dd-page-in, .docdoe-student-os .dd-entry { opacity: 1; } }