Old rule `li input[type="checkbox"] + *` absolutely-positioned the first element sibling after the checkbox (typically <a>, <code>, <strong>), yanking links and code spans out of flow and overlapping adjacent content in the rendered PDF. Replace with a targeted rule that styles the native disabled checkbox inline (small green box) and leaves siblings untouched. Pandoc GFM emits `<li><input disabled type="checkbox"> text…</li>` with no wrapper class, so we target `li > input[type="checkbox"]` directly. Co-Authored-By: Claude <noreply@anthropic.com>
480 lines
11 KiB
CSS
480 lines
11 KiB
CSS
/*
|
|
* ZenQuality — client handover stylesheet
|
|
* Used to render LIVRAISON.md / HANDOVER.md as a branded HTML/PDF.
|
|
* Source brand tokens: zenquality.fr (CSS custom properties extracted from
|
|
* the live site) — Inter (body) + Playfair Display (headings), green palette.
|
|
*/
|
|
|
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Playfair+Display:wght@400;600;700&display=swap');
|
|
|
|
:root {
|
|
--green-dark: #1A3A25;
|
|
--green-forest: #2D5A3D;
|
|
--green-moss: #4A7C59;
|
|
--green-sage: #87A878;
|
|
--black-deep: #0A0A0A;
|
|
--black-soft: #1A1A1A;
|
|
--gray-dark: #2A2A2A;
|
|
--gray-mid: #666666;
|
|
--gray-light: #B0B0B0;
|
|
--white-cream: #F5F0EB;
|
|
--white-pure: #FFFFFF;
|
|
|
|
--status-ok: #2D5A3D;
|
|
--status-warn: #b58900;
|
|
--status-fail: #a83232;
|
|
}
|
|
|
|
@page {
|
|
size: A4;
|
|
margin: 22mm 18mm 22mm 18mm;
|
|
@top-right {
|
|
content: string(doctitle);
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 8.5pt;
|
|
color: var(--green-moss);
|
|
}
|
|
@bottom-right {
|
|
content: counter(page) " / " counter(pages);
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 8.5pt;
|
|
color: var(--gray-mid);
|
|
}
|
|
@bottom-left {
|
|
content: "ZenQuality — zenquality.fr";
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 8.5pt;
|
|
color: var(--gray-mid);
|
|
}
|
|
}
|
|
|
|
@page :first {
|
|
margin: 0;
|
|
@top-right { content: ""; }
|
|
@bottom-right { content: ""; }
|
|
@bottom-left { content: ""; }
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
|
|
html, body {
|
|
margin: 0;
|
|
padding: 0;
|
|
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
font-size: 10.5pt;
|
|
line-height: 1.6;
|
|
color: var(--black-deep);
|
|
background: var(--white-pure);
|
|
}
|
|
|
|
/* ============ COVER PAGE ============ */
|
|
.cover {
|
|
page-break-after: always;
|
|
height: 297mm;
|
|
width: 210mm;
|
|
padding: 35mm 22mm 22mm 22mm;
|
|
background:
|
|
radial-gradient(ellipse at top right, rgba(135, 168, 120, 0.18) 0%, transparent 55%),
|
|
radial-gradient(ellipse at bottom left, rgba(45, 90, 61, 0.06) 0%, transparent 55%),
|
|
var(--white-pure);
|
|
color: var(--black-deep);
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
page: cover;
|
|
}
|
|
|
|
.cover-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.cover-logo {
|
|
width: 55mm;
|
|
height: auto;
|
|
max-height: 30mm;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.cover-tagline {
|
|
font-family: 'Playfair Display', Georgia, serif;
|
|
font-size: 10pt;
|
|
font-style: italic;
|
|
color: var(--green-forest);
|
|
text-align: right;
|
|
max-width: 70mm;
|
|
margin-top: 6mm;
|
|
}
|
|
|
|
.cover-body {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
margin: -10mm 0 0 0;
|
|
}
|
|
|
|
.cover-eyebrow {
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 9pt;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.18em;
|
|
color: var(--green-forest);
|
|
margin-bottom: 6mm;
|
|
}
|
|
|
|
.cover-title {
|
|
font-family: 'Playfair Display', Georgia, serif;
|
|
font-size: 34pt;
|
|
font-weight: 700;
|
|
color: var(--black-deep);
|
|
line-height: 1.1;
|
|
margin: 0 0 6mm 0;
|
|
letter-spacing: -0.015em;
|
|
}
|
|
|
|
.cover-subtitle {
|
|
font-family: 'Playfair Display', Georgia, serif;
|
|
font-size: 16pt;
|
|
font-weight: 400;
|
|
font-style: italic;
|
|
color: var(--green-forest);
|
|
margin: 0 0 18mm 0;
|
|
max-width: 140mm;
|
|
}
|
|
|
|
.cover-meta {
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 10.5pt;
|
|
color: var(--black-deep);
|
|
line-height: 1.9;
|
|
border-left: 2px solid var(--green-forest);
|
|
padding-left: 5mm;
|
|
}
|
|
|
|
.cover-meta strong {
|
|
color: var(--green-forest);
|
|
font-weight: 600;
|
|
display: inline-block;
|
|
min-width: 25mm;
|
|
}
|
|
|
|
.cover-meta a {
|
|
color: var(--black-deep);
|
|
text-decoration: underline;
|
|
text-decoration-color: rgba(45, 90, 61, 0.6);
|
|
}
|
|
|
|
.cover-footer {
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 9pt;
|
|
color: var(--green-forest);
|
|
border-top: 1px solid rgba(45, 90, 61, 0.4);
|
|
padding-top: 5mm;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.cover-footer a {
|
|
color: var(--black-deep);
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.cover-footer a:hover { color: var(--green-forest); }
|
|
|
|
/* ============ DOCUMENT BODY ============ */
|
|
.content {
|
|
string-set: doctitle attr(data-title);
|
|
}
|
|
|
|
h1 {
|
|
font-family: 'Playfair Display', Georgia, serif;
|
|
font-size: 22pt;
|
|
font-weight: 700;
|
|
color: var(--green-dark);
|
|
margin: 0 0 6mm 0;
|
|
page-break-after: avoid;
|
|
string-set: doctitle content();
|
|
}
|
|
|
|
h2 {
|
|
font-family: 'Playfair Display', Georgia, serif;
|
|
font-size: 17pt;
|
|
font-weight: 600;
|
|
color: var(--green-forest);
|
|
margin: 12mm 0 4mm 0;
|
|
padding-bottom: 2.5mm;
|
|
border-bottom: 2px solid var(--green-sage);
|
|
page-break-before: always;
|
|
page-break-after: avoid;
|
|
}
|
|
|
|
.content > h2:first-of-type,
|
|
h2.no-break,
|
|
h2.continue {
|
|
page-break-before: auto;
|
|
}
|
|
|
|
h3 {
|
|
font-family: 'Playfair Display', Georgia, serif;
|
|
font-size: 13.5pt;
|
|
font-weight: 600;
|
|
color: var(--green-forest);
|
|
margin: 8mm 0 3mm 0;
|
|
page-break-after: avoid;
|
|
}
|
|
|
|
h4 {
|
|
font-family: 'Inter', sans-serif;
|
|
font-size: 10pt;
|
|
font-weight: 600;
|
|
color: var(--green-moss);
|
|
margin: 6mm 0 2mm 0;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
page-break-after: avoid;
|
|
}
|
|
|
|
p { margin: 0 0 3mm 0; }
|
|
p, li { orphans: 3; widows: 3; }
|
|
|
|
ul, ol { margin: 0 0 3mm 0; padding-left: 6mm; }
|
|
ul li, ol li { margin: 0 0 1.5mm 0; }
|
|
|
|
ul li::marker { color: var(--green-moss); }
|
|
ol li::marker { color: var(--green-moss); font-weight: 600; }
|
|
|
|
/* ============ PAGE-BREAK HARDENING ============ */
|
|
/* Keep each list item intact across pages — prevents the bullet/marker
|
|
from staying on the previous page while the text reflows to the next
|
|
(historical cause of "trailing word + leading bullet" superposition). */
|
|
li {
|
|
page-break-inside: avoid;
|
|
break-inside: avoid;
|
|
}
|
|
/* Tie the first block after a heading to the heading itself so a page
|
|
break never splits "heading + intro" or "heading + first list item"
|
|
across two pages. */
|
|
h1 + p, h1 + ul, h1 + ol,
|
|
h2 + p, h2 + ul, h2 + ol,
|
|
h3 + p, h3 + ul, h3 + ol,
|
|
h4 + p, h4 + ul, h4 + ol {
|
|
page-break-before: avoid;
|
|
break-before: avoid;
|
|
}
|
|
|
|
strong { color: var(--green-dark); font-weight: 600; }
|
|
|
|
em { color: var(--green-forest); font-style: italic; }
|
|
|
|
blockquote {
|
|
border-left: 3px solid var(--green-moss);
|
|
padding: 3mm 5mm;
|
|
margin: 4mm 0;
|
|
background: var(--white-cream);
|
|
color: var(--gray-dark);
|
|
font-style: italic;
|
|
page-break-inside: avoid;
|
|
}
|
|
|
|
blockquote p:last-child { margin-bottom: 0; }
|
|
|
|
a { color: var(--green-forest); text-decoration: underline; text-decoration-thickness: 0.5pt; text-underline-offset: 1.5pt; }
|
|
a:hover { color: var(--green-dark); }
|
|
|
|
code {
|
|
font-family: 'JetBrains Mono', 'Fira Code', Menlo, monospace;
|
|
font-size: 9pt;
|
|
background: var(--white-cream);
|
|
padding: 0.5mm 1.5mm;
|
|
border-radius: 1mm;
|
|
color: var(--green-dark);
|
|
}
|
|
|
|
pre {
|
|
background: var(--white-cream);
|
|
padding: 4mm 5mm;
|
|
border-radius: 1.5mm;
|
|
border-left: 3px solid var(--green-moss);
|
|
font-size: 8.5pt;
|
|
line-height: 1.45;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
page-break-inside: avoid;
|
|
margin: 4mm 0;
|
|
}
|
|
|
|
pre code { background: none; padding: 0; color: var(--black-deep); font-size: inherit; }
|
|
|
|
/* ============ TABLES ============ */
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 4mm 0;
|
|
font-size: 9.5pt;
|
|
page-break-inside: avoid;
|
|
}
|
|
|
|
th {
|
|
font-family: 'Inter', sans-serif;
|
|
background: var(--green-forest);
|
|
color: var(--white-pure);
|
|
text-align: left;
|
|
padding: 2.5mm 3mm;
|
|
font-weight: 600;
|
|
font-size: 9pt;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
border-bottom: 0;
|
|
}
|
|
|
|
td {
|
|
padding: 2.5mm 3mm;
|
|
border-bottom: 1px solid var(--green-sage);
|
|
vertical-align: top;
|
|
}
|
|
|
|
tr:nth-child(even) td { background: rgba(245, 240, 235, 0.55); }
|
|
|
|
/* Numeric / status cols of score tables auto-detected via header text */
|
|
table th:nth-child(2),
|
|
table th:nth-child(3),
|
|
table th:nth-child(4),
|
|
table td:nth-child(2),
|
|
table td:nth-child(3),
|
|
table td:nth-child(4) {
|
|
text-align: right;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
table th:last-child,
|
|
table td:last-child {
|
|
text-align: center;
|
|
}
|
|
|
|
/* ============ CHECKLISTS ============ */
|
|
ul.checklist,
|
|
ul.task-list {
|
|
list-style: none;
|
|
padding-left: 0;
|
|
}
|
|
|
|
ul.checklist li,
|
|
ul.task-list li {
|
|
padding-left: 8mm;
|
|
position: relative;
|
|
margin-bottom: 2.5mm;
|
|
}
|
|
|
|
ul.checklist li::before,
|
|
ul.task-list li::before,
|
|
li.task-list-item::before {
|
|
content: "☐";
|
|
position: absolute;
|
|
left: 0;
|
|
color: var(--green-moss);
|
|
font-size: 12pt;
|
|
line-height: 1;
|
|
}
|
|
|
|
/* Pandoc GFM emits <li><input disabled type="checkbox"> text...</li> with
|
|
no wrapper class. Render the native checkbox inline (small, green) and
|
|
leave inline elements (<a>, <code>, <strong>) that follow it untouched.
|
|
Earlier rule `li input[type="checkbox"] + *` mistakenly absolutely-
|
|
positioned the first element sibling after the checkbox, yanking links
|
|
and code spans out of flow and overlapping adjacent content. */
|
|
li > input[type="checkbox"] {
|
|
appearance: none;
|
|
-webkit-appearance: none;
|
|
display: inline-block;
|
|
width: 3mm;
|
|
height: 3mm;
|
|
margin: 0 1.5mm 0 0;
|
|
border: 0.4mm solid var(--green-moss);
|
|
border-radius: 0.5mm;
|
|
vertical-align: middle;
|
|
background: transparent;
|
|
}
|
|
|
|
li > input[type="checkbox"]:checked {
|
|
background: var(--green-forest);
|
|
border-color: var(--green-forest);
|
|
}
|
|
|
|
/* ============ CALLOUTS ============ */
|
|
.callout {
|
|
padding: 4mm 6mm;
|
|
margin: 4mm 0;
|
|
border-radius: 2mm;
|
|
page-break-inside: avoid;
|
|
font-size: 10pt;
|
|
}
|
|
|
|
.callout.info {
|
|
background: var(--white-cream);
|
|
border-left: 4px solid var(--green-moss);
|
|
}
|
|
|
|
.callout.warn {
|
|
background: #fdf6e3;
|
|
border-left: 4px solid var(--status-warn);
|
|
}
|
|
|
|
.callout.success {
|
|
background: rgba(135, 168, 120, 0.14);
|
|
border-left: 4px solid var(--green-forest);
|
|
}
|
|
|
|
.callout-title {
|
|
font-family: 'Inter', sans-serif;
|
|
font-weight: 600;
|
|
font-size: 10pt;
|
|
color: var(--green-dark);
|
|
margin-bottom: 2mm;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
|
|
/* ============ SECTION DIVIDERS ============ */
|
|
hr {
|
|
border: none;
|
|
border-top: 1px solid var(--green-sage);
|
|
margin: 8mm 0;
|
|
}
|
|
|
|
/* ============ STATUS PILLS (used by text replacement) ============ */
|
|
.status-ok { color: var(--status-ok); font-weight: 600; }
|
|
.status-warn { color: var(--status-warn); font-weight: 600; }
|
|
.status-fail { color: var(--status-fail); font-weight: 600; }
|
|
|
|
/* ============ LINK BEHAVIOR IN PRINT ============ */
|
|
@media print {
|
|
a[href^="http"]::after {
|
|
content: " (" attr(href) ")";
|
|
font-size: 7.5pt;
|
|
color: var(--gray-mid);
|
|
font-style: italic;
|
|
font-weight: 400;
|
|
}
|
|
a[href^="#"]::after,
|
|
a[href^="mailto:"]::after,
|
|
a[href^="tel:"]::after,
|
|
a.bare-url::after,
|
|
.cover a::after,
|
|
table a::after { content: ""; }
|
|
/* Belt-and-braces: prevent the ::after URL pseudo-element from breaking
|
|
across pages or columns and overlapping the next block (root cause of
|
|
historical "text superposition" bugs on long URLs). */
|
|
a[href^="http"]::after {
|
|
white-space: nowrap;
|
|
page-break-before: avoid;
|
|
page-break-inside: avoid;
|
|
break-before: avoid;
|
|
break-inside: avoid;
|
|
}
|
|
}
|