mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-05-07 18:18:42 -05:00
- Create shared/ directory with centralized SCSS partials and site-head.html so site subsites (about, community, newsletter) no longer duplicate inline header config or reference book-only styles - Fix subscribe modal: change script src from broken relative path (../../book/quarto/assets/scripts/subscribe-modal.js) to absolute URL (https://mlsysbook.ai/vol1/assets/scripts/subscribe-modal.js) which the rewrite-dev-urls.sh script converts for dev preview automatically
638 lines
15 KiB
SCSS
638 lines
15 KiB
SCSS
// =============================================================================
|
|
// BOOK-ONLY STYLES — Textbook-specific styles (Vol1 & Vol2 only)
|
|
// =============================================================================
|
|
// These styles are NOT shared with kits, labs, instructors, or site pages.
|
|
// They handle foldbox callout exclusions, margin chapter connections, code
|
|
// listings, announcement bars, and other textbook-specific UI.
|
|
// =============================================================================
|
|
|
|
/* Remove any interfering styles from definition callouts - let foldbox handle everything */
|
|
|
|
/* Hide empty paragraphs in custom callouts that are generated by the extension */
|
|
.callout-definition>p:empty,
|
|
.callout-definition>p:first-child:empty,
|
|
details.callout-definition p:empty,
|
|
details.callout-definition>div>p:empty,
|
|
details.callout-definition>div>p:first-child:empty,
|
|
details.callout-definition>div>p:last-child:empty,
|
|
.callout-colab>p:empty,
|
|
.callout-colab>p:first-child:empty,
|
|
details.callout-colab p:empty,
|
|
details.callout-colab>div>p:empty,
|
|
details.callout-colab>div>p:first-child:empty,
|
|
details.callout-colab>div>p:last-child:empty {
|
|
display: none !important;
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
height: 0 !important;
|
|
line-height: 0 !important;
|
|
}
|
|
|
|
/* Exclude all custom foldbox callouts from general callout styling - let foldbox handle everything */
|
|
.callout.callout-quiz-question,
|
|
.callout.callout-quiz-answer,
|
|
.callout.callout-definition,
|
|
.callout.callout-example,
|
|
.callout.callout-colab,
|
|
.callout.callout-notebook,
|
|
.callout.callout-lighthouse,
|
|
.callout.callout-perspective,
|
|
.callout.callout-checkpoint,
|
|
.callout.callout-theorem,
|
|
.callout.callout-principle,
|
|
.callout.callout-takeaways,
|
|
.callout.callout-chapter-connection,
|
|
.callout.callout-chapter-forward,
|
|
.callout.callout-chapter-recall,
|
|
.callout.callout-resource-slides,
|
|
.callout.callout-resource-videos,
|
|
.callout.callout-resource-exercises,
|
|
.callout.callout-code {
|
|
margin: 0 !important;
|
|
/* Let foldbox.css handle the margin */
|
|
border: none !important;
|
|
/* Remove any borders from wrapper */
|
|
box-shadow: none !important;
|
|
/* Remove any shadows from wrapper */
|
|
background: transparent !important;
|
|
/* Make wrapper transparent */
|
|
text-align: left !important;
|
|
/* Ensure left alignment */
|
|
}
|
|
|
|
/* Ensure content inside foldbox callouts is left-aligned */
|
|
/* Note: Most alignment is handled by foldbox.css; this is minimal override for Quarto defaults */
|
|
.callout.callout-quiz-question div,
|
|
.callout.callout-quiz-answer div,
|
|
.callout.callout-definition div,
|
|
.callout.callout-example div,
|
|
.callout.callout-colab div,
|
|
.callout.callout-notebook div,
|
|
.callout.callout-lighthouse div,
|
|
.callout.callout-perspective div,
|
|
.callout.callout-checkpoint div,
|
|
.callout.callout-theorem div,
|
|
.callout.callout-principle div,
|
|
.callout.callout-takeaways div,
|
|
.callout.callout-chapter-connection div,
|
|
.callout.callout-chapter-forward div,
|
|
.callout.callout-chapter-recall div,
|
|
.callout.callout-resource-slides div,
|
|
.callout.callout-resource-videos div,
|
|
.callout.callout-resource-exercises div,
|
|
.callout.callout-code div {
|
|
text-align: left !important;
|
|
}
|
|
|
|
/* Override slimcontent layout to match regular floating layout */
|
|
@media (min-width: 992px) {
|
|
body.floating.slimcontent .page-columns {
|
|
grid-template-columns: [screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end] !important;
|
|
}
|
|
}
|
|
|
|
// Fix Hypothesis margin that prevents full-width elements
|
|
body.hypothesis-enabled #quarto-header,
|
|
body.hypothesis-enabled .headroom-target,
|
|
body.hypothesis-enabled header.headroom {
|
|
margin-right: 0 !important;
|
|
}
|
|
|
|
// Enhanced announcement styling with solid background (no transparency)
|
|
.alert-primary,
|
|
.announcement {
|
|
background: linear-gradient(135deg,
|
|
lighten($accent, 52%) 0%,
|
|
lighten($accent, 54%) 100%) !important;
|
|
border-color: rgba($accent, 0.4) !important;
|
|
border-left: 4px solid $accent !important;
|
|
color: darken($accent, 25%) !important;
|
|
// Break out of parent container to span full viewport width
|
|
// Transform-based centering ignores parent margins
|
|
position: relative !important;
|
|
left: 50% !important;
|
|
transform: translateX(-50%) !important;
|
|
width: 100vw !important;
|
|
max-width: 100vw !important;
|
|
margin-left: 0 !important;
|
|
margin-right: 0 !important;
|
|
box-sizing: border-box !important;
|
|
|
|
// Dismiss button (X)
|
|
.btn-close {
|
|
opacity: 0.6 !important;
|
|
|
|
&:hover {
|
|
opacity: 1 !important;
|
|
}
|
|
}
|
|
|
|
a {
|
|
color: $accent !important;
|
|
font-weight: 500;
|
|
|
|
&:hover {
|
|
color: darken($accent, 15%) !important;
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
|
|
// Typography hierarchy for better readability
|
|
strong,
|
|
b {
|
|
color: darken($accent, 30%) !important;
|
|
font-weight: 600;
|
|
}
|
|
|
|
// Ensure icons and other elements inherit the color scheme
|
|
.bi,
|
|
i {
|
|
color: $accent !important;
|
|
}
|
|
|
|
// Callout icons override the global accent color (more specific selectors)
|
|
.callout .callout-icon .bi,
|
|
.callout .callout-icon i,
|
|
div[class*="callout"] .callout-icon .bi,
|
|
div[class*="callout"] .callout-icon i {
|
|
color: inherit !important;
|
|
}
|
|
|
|
// Remove background from ::before pseudo-elements on icon fonts
|
|
i.callout-icon::before,
|
|
.callout-icon i::before {
|
|
background-color: transparent !important;
|
|
background: none !important;
|
|
}
|
|
}
|
|
|
|
// Abstract section styles for homepage
|
|
.abstract-section {
|
|
display: flex;
|
|
gap: 40px;
|
|
align-items: flex-start;
|
|
margin: 30px 0;
|
|
}
|
|
|
|
.abstract-content {
|
|
flex: 1;
|
|
}
|
|
|
|
.book-card {
|
|
flex-shrink: 0;
|
|
width: 300px;
|
|
text-align: center;
|
|
padding: 25px 15px;
|
|
background: linear-gradient(135deg, #fefefe 0%, #f8f9fa 50%, #f0f2f5 100%);
|
|
border: 1px solid #e8eaed;
|
|
border-radius: 16px;
|
|
box-shadow: 0 8px 32px rgba($accent, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04);
|
|
}
|
|
|
|
.book-image {
|
|
width: 100%;
|
|
max-width: 240px;
|
|
height: auto;
|
|
margin-bottom: 18px;
|
|
}
|
|
|
|
.book-card-link {
|
|
text-decoration: none;
|
|
color: inherit;
|
|
display: block;
|
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
|
}
|
|
|
|
.book-card-link:hover {
|
|
transform: scale(1.02);
|
|
}
|
|
|
|
.book-card-link:hover .book-card {
|
|
box-shadow: 0 12px 40px rgba($accent, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
}
|
|
|
|
.book-title {
|
|
margin: 0 0 6px 0;
|
|
color: #495057;
|
|
font-size: 1em;
|
|
font-weight: 600;
|
|
text-shadow: none;
|
|
}
|
|
|
|
.book-subtitle {
|
|
margin: 0;
|
|
color: #6c757d;
|
|
font-size: 0.9em;
|
|
font-weight: 600;
|
|
letter-spacing: 0.3px;
|
|
}
|
|
|
|
// Responsive styles for abstract section
|
|
@media (max-width: 768px) {
|
|
.abstract-section {
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
}
|
|
|
|
.abstract-content {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.book-card-link {
|
|
width: 100%;
|
|
max-width: 300px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.book-card {
|
|
padding: 15px 10px;
|
|
}
|
|
|
|
.book-image {
|
|
max-width: 200px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.book-title {
|
|
font-size: 1em;
|
|
}
|
|
|
|
.book-subtitle {
|
|
font-size: 0.85em;
|
|
}
|
|
}
|
|
|
|
// Support mission section - call-to-action box
|
|
.support-mission {
|
|
background-color: #f8f9fa;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 8px;
|
|
padding: 1.5rem;
|
|
margin: 2rem 0;
|
|
|
|
p {
|
|
color: #495057;
|
|
line-height: 1.6;
|
|
margin-bottom: 1.5rem;
|
|
|
|
&:first-child {
|
|
margin-top: 0;
|
|
}
|
|
|
|
&.support-note {
|
|
margin: 1rem 0 0 0;
|
|
font-size: 0.9rem;
|
|
color: #6c757d;
|
|
}
|
|
}
|
|
|
|
a {
|
|
color: $accent;
|
|
text-decoration: none;
|
|
|
|
&:hover {
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean podcast section for homepage
|
|
.podcast-section {
|
|
background-color: #f8f9fa;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 8px;
|
|
padding: 1.5rem;
|
|
margin: 2rem 0;
|
|
|
|
p {
|
|
color: #495057;
|
|
line-height: 1.6;
|
|
margin-bottom: 1.5rem;
|
|
|
|
&:first-child {
|
|
margin-top: 0;
|
|
}
|
|
}
|
|
|
|
a {
|
|
color: $accent;
|
|
text-decoration: none;
|
|
|
|
&:hover {
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
|
|
audio {
|
|
width: 100%;
|
|
height: 36px;
|
|
margin-top: 0.5rem;
|
|
}
|
|
}
|
|
|
|
.support-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin: 1.5rem 0;
|
|
|
|
.star-count {
|
|
background-color: #ffffff;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 6px;
|
|
padding: 0.5rem 1rem;
|
|
font-weight: 600;
|
|
color: #495057;
|
|
font-size: 0.9rem;
|
|
|
|
&::before {
|
|
content: "⭐ ";
|
|
color: #6c757d;
|
|
}
|
|
}
|
|
|
|
.github-star-btn {
|
|
background-color: $accent !important;
|
|
color: white !important;
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 6px;
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
font-size: 0.9rem;
|
|
transition: all 0.2s ease;
|
|
border: none;
|
|
|
|
&:hover {
|
|
background-color: darken($accent, 8%) !important;
|
|
color: white !important;
|
|
text-decoration: none;
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mobile responsive for book-only sections
|
|
@media (max-width: 768px) {
|
|
|
|
.support-mission,
|
|
.podcast-section {
|
|
padding: 1.25rem;
|
|
margin: 1.5rem 0;
|
|
}
|
|
|
|
.support-actions {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
gap: 0.75rem;
|
|
|
|
.github-star-btn {
|
|
text-align: center;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Chapter connections in margin for HTML - clean and minimal
|
|
.margin-container {
|
|
position: relative;
|
|
|
|
.margin-chapter-connection {
|
|
// Position in the right margin, avoiding footnote conflicts
|
|
position: absolute;
|
|
right: -250px; // Adjust based on your layout's margin width
|
|
top: -20px; // Offset upward to avoid footnotes below
|
|
width: 220px; // Slightly smaller than the positioning offset
|
|
background-color: transparent;
|
|
border: none;
|
|
border-left: 2px solid rgba($accent, 0.4);
|
|
border-radius: 0;
|
|
padding: 6px 0 6px 10px;
|
|
font-size: 0.7rem; // Made even smaller
|
|
line-height: 1.2;
|
|
color: #777; // Slightly lighter
|
|
z-index: 5; // Lower z-index than footnotes
|
|
|
|
// Alternative positioning to avoid footnotes completely
|
|
&.avoid-footnotes {
|
|
position: sticky;
|
|
top: 100px;
|
|
float: right;
|
|
clear: both;
|
|
margin: -30px -250px 20px 20px;
|
|
background-color: rgba(255, 255, 255, 0.95);
|
|
padding: 8px 10px;
|
|
border-radius: 4px;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
// Make it collapse nicely on smaller screens
|
|
@media (max-width: 1400px) {
|
|
position: static;
|
|
right: auto;
|
|
width: auto;
|
|
margin: 1rem 0;
|
|
|
|
&.avoid-footnotes {
|
|
position: static;
|
|
float: none;
|
|
margin: 1rem 0;
|
|
background: transparent;
|
|
box-shadow: none;
|
|
border-radius: 0;
|
|
}
|
|
}
|
|
|
|
// Style the header more subtly
|
|
.callout-header {
|
|
font-weight: 500;
|
|
color: #999; // Even more subtle
|
|
font-size: 0.65rem; // Smaller header
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
margin-bottom: 4px; // Tighter spacing
|
|
display: block;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
// Style the connection list
|
|
ul,
|
|
ol {
|
|
margin: 0;
|
|
padding-left: 12px; // Tighter indent
|
|
|
|
li {
|
|
margin-bottom: 4px; // Tighter spacing
|
|
font-size: 0.7rem; // Smaller text
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Style paragraph content
|
|
p {
|
|
margin: 0 0 4px 0;
|
|
font-size: 0.7rem;
|
|
line-height: 1.2;
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
|
|
// Style links within connections - more subtle
|
|
a {
|
|
color: #777;
|
|
text-decoration: none;
|
|
|
|
&:hover {
|
|
color: $accent;
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Enhanced styling for code listings - more prominent */
|
|
.listing figure {
|
|
margin: 2.5rem 0 !important;
|
|
/* Even more space around listings */
|
|
border: 2px solid #D1D7E0;
|
|
/* Slate border */
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
box-shadow: 0 2px 8px rgba($accent, 0.1) !important;
|
|
/* Match callout subtle shadow */
|
|
background: linear-gradient(135deg, #F2F4F8 0%, #ffffff 100%);
|
|
/* Light blue-gray background */
|
|
position: relative;
|
|
}
|
|
|
|
/* Code block within listings */
|
|
.listing pre {
|
|
margin: 0 !important;
|
|
border-radius: 0 !important;
|
|
border: none !important;
|
|
}
|
|
|
|
/* Listing captions - base style */
|
|
.listing figcaption,
|
|
.listing .listing-caption {
|
|
background: linear-gradient(135deg, #F7F9FC 0%, #EDF2F7 100%) !important;
|
|
/* Very light cool gray-blue gradient */
|
|
border-bottom: 2px solid #D1D7E0 !important;
|
|
/* Soft slate gray border */
|
|
padding: 1rem 1.25rem !important;
|
|
/* More padding */
|
|
margin: 0 !important;
|
|
font-size: 0.95rem !important;
|
|
/* Slightly larger text */
|
|
color: #1a202c !important;
|
|
/* Darker text */
|
|
font-family: var(--bs-body-font-family, system-ui, sans-serif) !important;
|
|
font-weight: 400 !important;
|
|
/* Default = normal weight */
|
|
line-height: 1.4 !important;
|
|
text-align: left !important;
|
|
order: -1;
|
|
/* Place caption at top */
|
|
position: relative;
|
|
}
|
|
|
|
/* Override global inheritance */
|
|
.listing figcaption *,
|
|
.listing .listing-caption * {
|
|
color: inherit !important;
|
|
font-weight: 400 !important;
|
|
/* Ensure normal unless overridden below */
|
|
}
|
|
|
|
/* Normal caption */
|
|
.listing figcaption {
|
|
font-weight: 400 !important;
|
|
}
|
|
|
|
/* Bold only first strong (label Listing X:) */
|
|
.listing figcaption strong:first-of-type {
|
|
font-weight: 700 !important;
|
|
}
|
|
|
|
/* Code content styling within listings */
|
|
.listing .sourceCode {
|
|
padding: 0.75rem 1rem !important;
|
|
/* Reduced padding to eliminate dead space */
|
|
background-color: #f1f3f4 !important;
|
|
/* More prominent gray background */
|
|
margin: 0 !important;
|
|
border: none !important;
|
|
}
|
|
|
|
/* Ensure no extra spacing in code blocks */
|
|
.listing .sourceCode pre,
|
|
.listing .sourceCode code {
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
}
|
|
|
|
/* Special styling for listings with bold/emphasized content in captions */
|
|
.listing figcaption strong,
|
|
.listing .listing-caption strong {
|
|
color: #1a202c !important;
|
|
/* Darker gray for better emphasis and hierarchy */
|
|
font-weight: 700 !important;
|
|
}
|
|
|
|
/* Minimal Video Styling */
|
|
.video-container {
|
|
margin: 1.5rem 0;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
border: 1px solid rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.video-container iframe {
|
|
border-radius: 8px;
|
|
}
|
|
|
|
/* Video in margin */
|
|
.margin-video {
|
|
margin: 1rem 0;
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
width: 100%;
|
|
}
|
|
|
|
/* Auto-numbering for margin videos */
|
|
body {
|
|
counter-reset: margin-video;
|
|
}
|
|
|
|
.margin-video {
|
|
counter-increment: margin-video;
|
|
}
|
|
|
|
.margin-video+p em::before {
|
|
content: "Video " counter(margin-video) ": ";
|
|
}
|
|
|
|
svg text {
|
|
font-family: "Nimbus Sans", "Helvetica", "Arial", sans-serif !important;
|
|
}
|
|
|
|
/* Chapter connection callouts - ensure left alignment */
|
|
.callout-chapter-connection {
|
|
text-align: left !important;
|
|
}
|
|
|
|
.callout-chapter-connection .callout-body {
|
|
text-align: left !important;
|
|
}
|
|
|
|
.callout-chapter-connection p {
|
|
text-align: left !important;
|
|
margin-bottom: 0.5rem;
|
|
}
|