Import the exercise builder
The drag-and-drop workspace for building BI122G exercise sheets, served by the Workshop at /projects/exercise-builder. Plain HTML, CSS and ES modules; no build step. It runs entirely in the browser — work in progress lives in localStorage and finished sheets leave as downloads, so nothing is written on the server. This directory is canonical. It began as a deployment target for deploy_builder.sh syncing from the BI122G course folder, and that arrangement has ended; see the README. Includes the sheet's light/dark switch: the stylesheet already carried both themes and followed the reader's system setting, so this adds the control that overrides it — a corner toggle built by sheet.js, applied before first paint by a head script the exporter writes, and hidden in print. The builder's toolbar previews the same attribute on the canvas. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ed5kU3HfZq9dfj7EYj5J2v
This commit is contained in:
+683
@@ -0,0 +1,683 @@
|
||||
/* ============================================================
|
||||
BI122G — Exercise 3
|
||||
|
||||
Palette from the university's own materials:
|
||||
#043554 the lecture deck's title-slide navy — masthead only
|
||||
#0969A8 HiS blue — the lecture-slide heading blue and the
|
||||
logo crest; the core, examinable track, plus
|
||||
structural rules and links
|
||||
#157539 HiS emerald — the side quests
|
||||
#B52E75 HiS ruby — reserved entirely for the protips
|
||||
graphite scale for text and rules.
|
||||
|
||||
Track system:
|
||||
core blue edge on the page ground
|
||||
side quest green tinted panel, dashed green edge
|
||||
protip ruby tinted band, ruby edge
|
||||
Each is distinguished by form as well as hue, so the
|
||||
distinction survives greyscale printing.
|
||||
|
||||
Type: Open Sans, as on the university site, with Cascadia
|
||||
Mono for terminal text — the face students see in VS Code.
|
||||
============================================================ */
|
||||
|
||||
:root{
|
||||
--paper: #FFFFFF;
|
||||
--surface: #F4F7FA;
|
||||
--sunk: #EAEFF4;
|
||||
--ink: #14181B;
|
||||
--ink-body: #313538;
|
||||
--ink-soft: #5C6165;
|
||||
--ink-faint: #7E858A;
|
||||
--rule: #DDE4EA;
|
||||
--rule-firm: #B4BFC7;
|
||||
|
||||
--green: #157539;
|
||||
--green-tint: #EBF4EF;
|
||||
--green-edge: #9AC7AC;
|
||||
|
||||
--blue: #0969A8;
|
||||
--blue-deep: #06507F;
|
||||
--blue-tint: #EAF3F9;
|
||||
--blue-edge: #9CC4DD;
|
||||
|
||||
--ruby: #B52E75;
|
||||
--ruby-tint: #FBEEF4;
|
||||
--ruby-edge: #E2A8C6;
|
||||
|
||||
/* which hue carries which track. Swap these two groups to flip it. */
|
||||
--core: var(--blue);
|
||||
--core-tint: var(--blue-tint);
|
||||
--core-edge: var(--blue-edge);
|
||||
--side: var(--green);
|
||||
--side-tint: var(--green-tint);
|
||||
--side-edge: var(--green-edge);
|
||||
|
||||
--term-bg: #17202A;
|
||||
--term-ink: #DDE4EA;
|
||||
--term-dim: #939CA3;
|
||||
--term-cue: #6FBCE8;
|
||||
--term-warn: #E8A26A;
|
||||
|
||||
--logo-filter: none;
|
||||
|
||||
--sans: "Open Sans", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
|
||||
--mono: "Cascadia Mono", "Cascadia Code", ui-monospace, "SF Mono", Menlo, "DejaVu Sans Mono", Consolas, monospace;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark){
|
||||
:root:not([data-theme="light"]){
|
||||
--paper: #0B0F12;
|
||||
--surface: #151B20;
|
||||
--sunk: #05080A;
|
||||
--ink: #F4F7FA;
|
||||
--ink-body: #D6DEE4;
|
||||
--ink-soft: #A6B0B8;
|
||||
--ink-faint: #808A92;
|
||||
--rule: #242C33;
|
||||
--rule-firm: #3A444C;
|
||||
|
||||
--green: #5DBE84;
|
||||
--green-tint:#0F2318;
|
||||
--green-edge:#35624A;
|
||||
|
||||
--blue: #6FBCE8;
|
||||
--blue-deep: #A5D6F2;
|
||||
--blue-tint: #0F2331;
|
||||
--blue-edge: #35617E;
|
||||
|
||||
--ruby: #E87AB0;
|
||||
--ruby-tint: #26141D;
|
||||
--ruby-edge: #7C4160;
|
||||
|
||||
--term-bg: #161D22;
|
||||
|
||||
--logo-filter: invert(1);
|
||||
}
|
||||
}
|
||||
|
||||
:root[data-theme="dark"]{
|
||||
--paper: #0B0F12;
|
||||
--surface: #151B20;
|
||||
--sunk: #05080A;
|
||||
--ink: #F4F7FA;
|
||||
--ink-body: #D6DEE4;
|
||||
--ink-soft: #A6B0B8;
|
||||
--ink-faint: #808A92;
|
||||
--rule: #242C33;
|
||||
--rule-firm: #3A444C;
|
||||
|
||||
--green: #5DBE84;
|
||||
--green-tint:#0F2318;
|
||||
--green-edge:#35624A;
|
||||
|
||||
--blue: #6FBCE8;
|
||||
--blue-deep: #A5D6F2;
|
||||
--blue-tint: #0F2331;
|
||||
--blue-edge: #35617E;
|
||||
|
||||
--ruby: #E87AB0;
|
||||
--ruby-tint: #26141D;
|
||||
--ruby-edge: #7C4160;
|
||||
|
||||
--term-bg: #161D22;
|
||||
|
||||
--logo-filter: invert(1);
|
||||
}
|
||||
|
||||
*{ box-sizing: border-box; }
|
||||
|
||||
body{
|
||||
margin: 0;
|
||||
background: var(--paper);
|
||||
color: var(--ink-body);
|
||||
font-family: var(--sans);
|
||||
font-size: 16.5px;
|
||||
line-height: 1.65;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.sheet{
|
||||
counter-reset: part; /* only the core parts take a number */
|
||||
max-width: 58rem;
|
||||
margin: 0 auto;
|
||||
padding: 2.5rem 1.5rem 6rem;
|
||||
}
|
||||
|
||||
/* ---------- masthead ---------- */
|
||||
|
||||
.masthead{ margin-bottom: 2.5rem; }
|
||||
|
||||
.logo{
|
||||
display: block;
|
||||
width: 13.5rem;
|
||||
max-width: 60%;
|
||||
height: auto;
|
||||
margin-bottom: 2.25rem;
|
||||
filter: var(--logo-filter);
|
||||
}
|
||||
|
||||
.eyebrow{
|
||||
font-size: .72rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: .14em;
|
||||
text-transform: uppercase;
|
||||
color: var(--blue);
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
h1{
|
||||
font-size: clamp(1.9rem, 4.6vw, 2.7rem);
|
||||
line-height: 1.14;
|
||||
font-weight: 700;
|
||||
/* white in the dark theme; a literal #fff would vanish on the light
|
||||
theme and in print, so this tracks the theme's strongest ink */
|
||||
color: var(--ink);
|
||||
margin: 0 0 .9rem;
|
||||
letter-spacing: -.015em;
|
||||
}
|
||||
/* the masthead spans the full column; the reading measure applies to
|
||||
body copy further down, not to the title block */
|
||||
.standfirst{
|
||||
font-size: 1.08rem;
|
||||
color: var(--ink);
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
border-top: 3px solid var(--blue);
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
/* ---------- generic type ---------- */
|
||||
|
||||
p{ margin: 0 0 1rem; max-width: 68ch; }
|
||||
h2, h3{ text-wrap: balance; }
|
||||
a{ color: var(--blue); text-underline-offset: .18em; }
|
||||
strong{ font-weight: 600; color: var(--ink); }
|
||||
|
||||
code{
|
||||
font-family: var(--mono);
|
||||
font-size: .87em;
|
||||
background: var(--sunk);
|
||||
border: 1px solid var(--rule);
|
||||
border-radius: 3px;
|
||||
padding: .06em .32em;
|
||||
white-space: nowrap;
|
||||
color: var(--ink);
|
||||
}
|
||||
h2 code, h3 code, .cmd code, .term code{ background: none; border: 0; padding: 0; }
|
||||
|
||||
kbd{
|
||||
font-family: var(--sans);
|
||||
font-size: .76em;
|
||||
font-weight: 600;
|
||||
background: var(--paper);
|
||||
border: 1px solid var(--rule-firm);
|
||||
border-bottom-width: 2px;
|
||||
border-radius: 4px;
|
||||
padding: .12em .45em;
|
||||
color: var(--ink);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ---------- legend ---------- */
|
||||
|
||||
.legend{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(14.5rem, 1fr));
|
||||
gap: .9rem;
|
||||
margin: 2.25rem 0 1rem;
|
||||
align-items: start;
|
||||
}
|
||||
.legend > div{
|
||||
padding: .85rem 1rem;
|
||||
font-size: .88rem;
|
||||
color: var(--ink-soft);
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
.legend .l-core{
|
||||
background: var(--core-tint);
|
||||
border: 1px solid var(--core-edge);
|
||||
border-left: 4px solid var(--core);
|
||||
}
|
||||
.legend .l-side{
|
||||
background: var(--side-tint);
|
||||
border: 1px dashed var(--side-edge);
|
||||
border-left: 4px solid var(--side);
|
||||
}
|
||||
.legend .l-protip{
|
||||
background: var(--ruby-tint);
|
||||
border: 1px solid var(--ruby-edge);
|
||||
border-left: 4px solid var(--ruby);
|
||||
}
|
||||
.legend b{
|
||||
display: block;
|
||||
font-size: .68rem;
|
||||
letter-spacing: .14em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: .3rem;
|
||||
color: var(--ink);
|
||||
}
|
||||
.legend .l-core b{ color: var(--core); }
|
||||
.legend .l-side b{ color: var(--side); }
|
||||
.legend .l-protip b{ color: var(--ruby); }
|
||||
|
||||
/* ---------- parts ---------- */
|
||||
|
||||
.part{
|
||||
display: grid;
|
||||
grid-template-columns: 5rem 1fr;
|
||||
gap: 0 2rem;
|
||||
padding-top: 2.5rem;
|
||||
margin-top: 2.5rem;
|
||||
border-top: 1px solid var(--rule);
|
||||
}
|
||||
.part:first-of-type{ border-top: 2px solid var(--blue); }
|
||||
.part:not(.is-side){ counter-increment: part; }
|
||||
|
||||
/* a side quest is not a step in the sequence, so it carries no number and
|
||||
its label sits out to the right, clear of the numbered spine */
|
||||
.part.is-side{ grid-template-columns: 1fr 6rem; }
|
||||
.part.is-side > .body{ grid-column: 1; }
|
||||
.part.is-side > .rail{ grid-column: 2; text-align: right; align-items: flex-end; }
|
||||
|
||||
.rail{
|
||||
font-size: .67rem;
|
||||
letter-spacing: .12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ink-faint);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .4rem;
|
||||
padding-top: .5rem;
|
||||
}
|
||||
.rail .num::before{ content: counter(part); }
|
||||
.rail .num{
|
||||
font-size: 2.1rem;
|
||||
font-weight: 700;
|
||||
line-height: .9;
|
||||
letter-spacing: -.03em;
|
||||
color: var(--rule-firm);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.rail .tag{ font-weight: 700; }
|
||||
.rail .tag.core{ color: var(--core); }
|
||||
.rail .tag.side{ color: var(--side); }
|
||||
|
||||
.part > .body{ min-width: 0; }
|
||||
.part h2{
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--core);
|
||||
margin: 0 0 .7rem;
|
||||
letter-spacing: -.012em;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.part.is-side h2{ color: var(--side); }
|
||||
|
||||
/* a whole side-quest part reads as one blue panel */
|
||||
.part.is-side > .body{
|
||||
background: var(--side-tint);
|
||||
border: 1px dashed var(--side-edge);
|
||||
border-left: 4px solid var(--side);
|
||||
border-radius: 0 5px 5px 0;
|
||||
padding: 1.2rem 1.4rem;
|
||||
}
|
||||
.part.is-side > .rail{ padding-top: 1.7rem; }
|
||||
|
||||
/* ---------- tasks ---------- */
|
||||
|
||||
ol.tasks{
|
||||
list-style: none;
|
||||
counter-reset: task;
|
||||
margin: 1.4rem 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.3rem;
|
||||
}
|
||||
ol.tasks > li{
|
||||
counter-increment: task;
|
||||
display: grid;
|
||||
grid-template-columns: 1.55rem 1fr;
|
||||
gap: 0 .8rem;
|
||||
min-width: 0;
|
||||
}
|
||||
ol.tasks > li::before{
|
||||
content: counter(task);
|
||||
font-size: .72rem;
|
||||
font-weight: 700;
|
||||
color: var(--paper);
|
||||
background: var(--core);
|
||||
border-radius: 50%;
|
||||
width: 1.55rem;
|
||||
height: 1.55rem;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
margin-top: .22rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.is-side ol.tasks > li::before{ background: var(--side); }
|
||||
ol.tasks > li > *{ grid-column: 2; min-width: 0; }
|
||||
ol.tasks > li > *:last-child{ margin-bottom: 0; }
|
||||
ol.tasks p{ margin-bottom: .6rem; }
|
||||
|
||||
/* ---------- command + terminal blocks ---------- */
|
||||
|
||||
.cmd, .term{
|
||||
margin: 0 0 .9rem;
|
||||
border-radius: 4px;
|
||||
font-family: var(--mono);
|
||||
font-size: .85rem;
|
||||
line-height: 1.7;
|
||||
position: relative;
|
||||
}
|
||||
.term{ overflow-x: auto; }
|
||||
|
||||
/* the whole block is the copy target, so nothing prints that
|
||||
would not also work on paper */
|
||||
.cmd{
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--rule);
|
||||
border-left: 3px solid var(--core);
|
||||
padding: .6rem 4.5rem .6rem .85rem;
|
||||
color: var(--ink);
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
cursor: pointer;
|
||||
}
|
||||
.cmd::before{
|
||||
content: "$";
|
||||
color: var(--core);
|
||||
padding-right: .55rem;
|
||||
user-select: none;
|
||||
}
|
||||
.cmd::after{
|
||||
content: "copy";
|
||||
position: absolute;
|
||||
top: .45rem;
|
||||
right: .7rem;
|
||||
font-family: var(--sans);
|
||||
font-size: .6rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: .1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ink-faint);
|
||||
opacity: 0;
|
||||
transition: opacity .15s ease;
|
||||
}
|
||||
.cmd:hover::after,
|
||||
.cmd:focus-visible::after{ opacity: 1; }
|
||||
.cmd.copied::after{ content: "copied"; opacity: 1; color: var(--core); }
|
||||
.cmd:focus-visible{ outline: 2px solid var(--core); outline-offset: 2px; }
|
||||
|
||||
/* inside blue territory the boxes sit on white so they stay legible */
|
||||
.is-side .cmd, .side-quest .cmd{
|
||||
background: var(--paper);
|
||||
border-left-color: var(--side);
|
||||
}
|
||||
.is-side .cmd::before, .side-quest .cmd::before{ color: var(--side); }
|
||||
.is-side .cmd.copied::after,
|
||||
.side-quest .cmd.copied::after{ color: var(--side); }
|
||||
|
||||
.term{
|
||||
background: var(--term-bg);
|
||||
color: var(--term-ink);
|
||||
padding: .8rem 1rem;
|
||||
white-space: pre;
|
||||
border: 1px solid var(--rule-firm);
|
||||
}
|
||||
.term .p{ color: var(--term-cue); }
|
||||
.term .c{ color: var(--term-ink); }
|
||||
.term .o{ color: var(--term-dim); }
|
||||
.term .e{ color: var(--term-warn); }
|
||||
.term .cap{
|
||||
display: block;
|
||||
font-family: var(--sans);
|
||||
font-size: .62rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: .13em;
|
||||
text-transform: uppercase;
|
||||
color: var(--term-dim);
|
||||
margin-bottom: .5rem;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* ---------- side quest ---------- */
|
||||
|
||||
.side-quest{
|
||||
border: 1px dashed var(--side-edge);
|
||||
border-left: 4px solid var(--side);
|
||||
background: var(--side-tint);
|
||||
padding: 1rem 1.15rem;
|
||||
margin: 1.5rem 0;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
/* nested inside an already-blue part, drop back to the page ground */
|
||||
.part.is-side .side-quest{ background: var(--paper); }
|
||||
|
||||
.side-quest > summary{
|
||||
font-size: .71rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .13em;
|
||||
text-transform: uppercase;
|
||||
color: var(--side);
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: .6rem;
|
||||
}
|
||||
.side-quest > summary::-webkit-details-marker{ display: none; }
|
||||
.side-quest > summary::after{
|
||||
content: "optional";
|
||||
font-size: .62rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: .08em;
|
||||
color: var(--ink-faint);
|
||||
}
|
||||
.side-quest > summary:focus-visible{ outline: 2px solid var(--side); outline-offset: 3px; }
|
||||
.side-quest > *:not(summary){ font-size: .95rem; }
|
||||
.side-quest > summary + *{ margin-top: .85rem; }
|
||||
.side-quest > *:last-child{ margin-bottom: 0; }
|
||||
|
||||
/* ---------- protip ---------- */
|
||||
|
||||
.protip{
|
||||
background: var(--ruby-tint);
|
||||
border: 1px solid var(--ruby-edge);
|
||||
border-left: 4px solid var(--ruby);
|
||||
border-radius: 0 4px 4px 0;
|
||||
padding: .8rem 1rem;
|
||||
margin: 1.4rem 0;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 0 .9rem;
|
||||
align-items: start;
|
||||
}
|
||||
.protip.headline{ border-width: 2px; border-left-width: 5px; }
|
||||
.protip .keys{ display: flex; gap: .25rem; padding-top: .12rem; }
|
||||
.protip .said{ margin: 0; font-size: .94rem; color: var(--ink-soft); max-width: 62ch; }
|
||||
.protip .said b{
|
||||
font-size: .67rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .16em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ruby);
|
||||
display: block;
|
||||
margin-bottom: .15rem;
|
||||
}
|
||||
.protip .said em{ font-style: italic; }
|
||||
|
||||
/* ---------- misc blocks ---------- */
|
||||
|
||||
.note{
|
||||
border-left: 3px solid var(--rule-firm);
|
||||
padding: .1rem 0 .1rem 1rem;
|
||||
margin: 1.3rem 0;
|
||||
color: var(--ink-soft);
|
||||
font-size: .95rem;
|
||||
}
|
||||
.note p:last-child{ margin-bottom: 0; }
|
||||
|
||||
.callout{
|
||||
background: var(--paper);
|
||||
border: 1px solid var(--core-edge);
|
||||
border-left: 4px solid var(--core);
|
||||
padding: 1rem 1.15rem;
|
||||
margin: 1.5rem 0;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
.callout h3{
|
||||
font-size: .71rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .13em;
|
||||
text-transform: uppercase;
|
||||
color: var(--core);
|
||||
margin: 0 0 .6rem;
|
||||
}
|
||||
.callout > *:last-child{ margin-bottom: 0; }
|
||||
|
||||
table{
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
font-size: .91rem;
|
||||
}
|
||||
.tablewrap{ overflow-x: auto; margin: 1.3rem 0; }
|
||||
.tablewrap table{ min-width: 28rem; }
|
||||
th, td{
|
||||
text-align: left;
|
||||
padding: .5rem .8rem .5rem 0;
|
||||
border-bottom: 1px solid var(--rule);
|
||||
vertical-align: top;
|
||||
}
|
||||
th{
|
||||
font-size: .67rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ink-faint);
|
||||
border-bottom-color: var(--rule-firm);
|
||||
}
|
||||
td code{ white-space: nowrap; }
|
||||
|
||||
ul.plain{ margin: 1rem 0; padding-left: 1.1rem; }
|
||||
ul.plain li{ margin-bottom: .45rem; max-width: 66ch; }
|
||||
|
||||
/* ---------- closing ---------- */
|
||||
|
||||
.closing{
|
||||
margin-top: 3.5rem;
|
||||
padding-top: 1.8rem;
|
||||
border-top: 2px solid var(--blue);
|
||||
}
|
||||
.closing h2{
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
color: var(--blue);
|
||||
margin: 0 0 .8rem;
|
||||
}
|
||||
|
||||
.colophon{
|
||||
margin-top: 3rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--rule);
|
||||
font-size: .74rem;
|
||||
color: var(--ink-faint);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .3rem 1.5rem;
|
||||
}
|
||||
|
||||
/* ---------- theme switch ---------- */
|
||||
|
||||
/* Built by sheet.js rather than written into the markup, so it exists
|
||||
only where it can actually work. It sits in the corner opposite the
|
||||
logo, above the reading column at every width. */
|
||||
.themetoggle{
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
z-index: 10;
|
||||
width: 2.1rem;
|
||||
height: 2.1rem;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 0;
|
||||
font-family: var(--sans);
|
||||
font-size: 1rem;
|
||||
line-height: 1;
|
||||
color: var(--ink-soft);
|
||||
background: var(--paper);
|
||||
border: 1px solid var(--rule-firm);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
transition: color .15s ease, border-color .15s ease;
|
||||
}
|
||||
.themetoggle:hover{ color: var(--blue); border-color: var(--blue); }
|
||||
.themetoggle:focus-visible{ outline: 2px solid var(--blue); outline-offset: 2px; }
|
||||
|
||||
/* ---------- narrow screens ---------- */
|
||||
|
||||
@media (max-width: 40rem){
|
||||
body{ font-size: 16px; }
|
||||
.sheet{ padding: 2rem 1.1rem 4rem; }
|
||||
.part{ grid-template-columns: 1fr; gap: .7rem; }
|
||||
.rail{ flex-direction: row; align-items: baseline; gap: .85rem; padding-top: 0; }
|
||||
.part.is-side{ grid-template-columns: 1fr; }
|
||||
.part.is-side > .body,
|
||||
.part.is-side > .rail{ grid-column: auto; }
|
||||
.part.is-side > .rail{ padding-top: 0; text-align: left; align-items: flex-start; }
|
||||
.part.is-side > .body{ padding: 1rem 1.1rem; }
|
||||
.rail .num{ font-size: 1.4rem; }
|
||||
ol.tasks > li{ grid-template-columns: 1.4rem 1fr; gap: 0 .6rem; }
|
||||
.cmd{ padding-right: .85rem; }
|
||||
.cmd::after{ display: none; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce){
|
||||
*{ animation: none !important; transition: none !important; }
|
||||
}
|
||||
|
||||
/* ---------- print / PDF ---------- */
|
||||
|
||||
@media print{
|
||||
/* `:root[data-theme]` and not a bare `:root`: the dark blocks above are
|
||||
attribute-qualified, so they outrank a plain :root here and a reader
|
||||
printing while in dark mode would get a page flooded with ink. Equal
|
||||
specificity and later in the file, so print wins either way. */
|
||||
:root, :root[data-theme]{
|
||||
--paper: #fff; --surface: #F4F7FA; --sunk: #EEF2F6;
|
||||
--ink: #000; --ink-body: #1a1c1e; --ink-soft: #3a3d40; --ink-faint: #5a5e62;
|
||||
--rule: #c4ccd3; --rule-firm: #8d959b;
|
||||
--green: #0F5A2B; --green-tint: #EDF5F0; --green-edge: #86B69B;
|
||||
--blue: #06537F; --blue-tint: #EDF4F9; --blue-edge: #7FAECB;
|
||||
--ruby: #96225F; --ruby-tint: #FBEFF5; --ruby-edge: #C98BAE;
|
||||
--logo-filter: none;
|
||||
}
|
||||
body{ font-size: 10.5pt; background: #fff; }
|
||||
.sheet{ max-width: none; padding: 0; }
|
||||
.themetoggle{ display: none; }
|
||||
.cmd{ cursor: auto; }
|
||||
.cmd::after{ content: none; }
|
||||
.part{ break-inside: avoid-page; page-break-inside: avoid; }
|
||||
ol.tasks > li,
|
||||
.side-quest, .protip, .callout, .cmd, .term{
|
||||
break-inside: avoid;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
.side-quest > summary::after{ content: " — optional"; }
|
||||
/* terminal blocks invert so they do not flood the page with ink */
|
||||
.term{ background: #F2F5F8; color: #000; border: 1px solid #8d959b; }
|
||||
.term .p{ color: #06537F; }
|
||||
.term .o{ color: #44484b; }
|
||||
.term .e{ color: #8a3410; }
|
||||
.term .cap{ color: #5a5e62; }
|
||||
a{ color: #000; text-decoration: underline; }
|
||||
a[href^="http"]::after{
|
||||
content: " (" attr(href) ")";
|
||||
font-size: .8em;
|
||||
color: #5a5e62;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user