diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c18dd8d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/README.md b/README.md index 69d2c41..a77676c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Shared Claude Code tooling for the team. Installs skills, conventions, and hooks ## What's included -- **Skills** — `/review-code`, `/review-security`, `/generate-pr`, `/handoff`, `/session-summary` +- **Skills** — `/review-code`, `/review-security`, `/generate-pr`, `/handoff`, `/session-summary`, plus `mindtwo-branding` (auto-activates when styling client- or team-facing deliverables such as Artifacts, reports, and PDF templates with the mindtwo corporate identity) - **CLAUDE.md** — Team conventions (code philosophy, architecture patterns, security rules) installed at `~/.claude/CLAUDE.md`, applying to all projects - **Hooks** — SessionStart update checker diff --git a/skills/mindtwo-branding/SKILL.md b/skills/mindtwo-branding/SKILL.md new file mode 100644 index 0000000..89d31d6 --- /dev/null +++ b/skills/mindtwo-branding/SKILL.md @@ -0,0 +1,184 @@ +--- +name: mindtwo-branding +description: Apply the mindtwo GmbH corporate identity to any client- or team-facing deliverable — Artifacts, HTML reports, one-pagers, slide decks, PDF templates, landing pages, email templates. Activates whenever a page or document is being designed or styled and it represents mindtwo, or when the user mentions CI, corporate identity, branding, brand colours, mindtwo Red, or Roobert. Do not activate for product UI inside a client application (those follow the client's own design system). +--- + +# mindtwo Corporate Identity + +The canonical implementation lives in the `mindtwo` repo (the agency website). When anything here is +ambiguous, that repo wins — it is the source of truth, not this file. + +| Asset | Path (relative to your local checkout of the `mindtwo` repo) | +|---|---| +| Markdown→PDF reference template | `resources/views/global/pdf/markdown-document.blade.php` | +| PDF chrome (top bar, footer, logo) | `app/Domains/Document/Actions/StreamMarkdownDocumentPdfAction.php` | +| Brand tokens | `resources/assets/css/mindtwo.css` (`@theme` block) | +| Written style spec | `resources/prompts/blog-featured-image.txt` + `blog-featured-image-styles/*.txt` | +| Roobert font family | `resources/assets/fonts/roobert/` | +| Logos (SVG) | `resources/assets/images/mindtwo/logo*.svg` | +| Logos (PNG/EPS, all colour spaces) | `public/downloads/logos/{rgb,cmyk,pantone}/` | + +## Brand constraints (non-negotiable) + +Wording +- Write the brand name lowercase everywhere: mindtwo — never Mindtwo, MindTwo, or + MINDTWO, even at the start of a sentence or in a heading (Brand Guide p. 12). +- German client-facing copy addresses the reader as Sie. Du/Dein is reserved for + employer-branding content (careers, benefits). Never mix the two in one deliverable + (pp. 2, 20, 22). +- The tagline is exactly "Build. Accelerate. Scale." — a period after each word, never + commas, never translated (pp. 2, 22, 27). + +Colour +- Red #DE0639 is an accent, ~10% of any layout. No red hero bands, red-filled cards, or + red page grounds. Light scheme: 60% #FFFFFF / 30% #121212 / 10% red; the dark scheme + swaps the first two (p. 15). +- The ground is #FFFFFF (light) or #121212 (dark) — never pure #000, never an invented + near-black. + +Type +- Roobert only; documented cuts are Light / Regular / Semibold / Bold (p. 19). Headings + at 600. +- Never: bold body text, justified text (Blocksatz), right-aligned text, all-caps + headlines or paragraphs (p. 20). Body is left-aligned, ragged right, neutral + letter-spacing. + +Logo +- Never recolour, rotate, distort, restyle, or re-proportion the logo; the wordmark's + first letter stays lowercase (p. 12). Clear space on every side ≥ the width of the + wordmark's "m"; minimum heights: horizontal 50px / vertical 78px / symbol 32px (p. 8). + +Geometry & imagery +- Corner radii 0–4px. Flat, geometric, sharp — no organic blobs, no glossy or plastic + 3D, no Corporate Memphis, no neon or aggressive gradients (pp. 27–29). + +For extended palette, logo variants, or anything not covered above, read +references/brand-rules.md before deciding. If both are silent, choose the most +conservative option and say so. Never invent a brand rule. + +## The three brand colours + +``` +mindtwo Red #DE0639 accent only — never a dominant surface +mindtwo Black #121212 deliberately NOT pure black +mindtwo White #FFFFFF +``` + +Red variants in production: `#9C182E` (dark), `#FF6470` (light). + +**The 60 / 30 / 10 rule is binding.** 60% white, 30% black, 10% red. Red is for highlights: an +eyebrow, a rule, a link, a single emphasised figure. A red hero band or a red-filled card breaks the +CI. The one documented exception is the "Red Stage" poster style for marketing imagery, which is not +a document style. + +Everything else is the Tailwind grey ramp, already established in the PDF template — do not invent +new neutrals: + +``` +#111827 headings #374151 body #6B7280 muted +#9CA3AF faint/meta #D1D5DB rule-strong #E5E7EB rule +#F3F4F6 surface-2 #F9FAFB surface +``` + +`references/tokens.css` has all of this as a ready-to-paste `:root` block with light and dark +definitions. Start from that file rather than retyping values. + +## Typeface + +**Roobert** across the board — Light 300 through Heavy 900, with italics. It is a geometric +sans: monolinear strokes, high x-height, wide proportions, double-storey g, round dots on i/j. +Headings sit at 600 (SemiBold) with negative tracking, never at 700+ unless the layout genuinely +needs the weight. + +`RoobertVF.woff2` (~90 KB) carries the whole weight axis in one file and is the right choice for a +web deliverable. Static weights are in the same directory if a variable font is not viable. + +⚠️ **Roobert is a commercial licence from Displaay Type Foundry.** Inlining it into a page that +gets shared by public link is a licensing decision, not a technical one — confirm the licence +covers it before shipping externally. For anything public where that is unresolved, use the +Arial fallback stack in `tokens.css` — Arial is the substitute the Brand Guide mandates (p. 21). + +Monospace, where code or figures appear: `ui-monospace, SFMono-Regular, Menlo, Consolas, monospace`. + +## Document patterns to reuse + +These come straight from the PDF template and are what makes a deliverable read as mindtwo: + +- **Eyebrow** — uppercase, ~0.75rem, `letter-spacing: .1em`, weight 600, red, with a `3px` red + left border and ~8px padding. This is the primary red moment on most pages. +- **Title** — weight 600, `letter-spacing: -.03em`, `line-height: 1.15`, in `#000` on light. +- **h2** — weight 600, `-.02em`, with a `1px solid #E5E7EB` bottom rule and padding beneath. +- **Links** — red, `text-decoration: none`. +- **Blockquote** — `3px` red left border on `#F9FAFB`, italic. +- **Tables** — `#F3F4F6` header cells, `2px solid #D1D5DB` under the head, `1px solid #E5E7EB` + between rows, no border on the last row, left-aligned headers, top-aligned cells. +- **Code** — inline on `#F3F4F6`; blocks on `#1A1A1A` with `#E5E7EB` text. +- **Callouts** — four semantic variants, `3px` left border + tinted background: + note `#3B82F6` / `#EFF6FF` / title `#1D4ED8` · tip `#10B981` / `#ECFDF5` / `#047857` · + caution `#F59E0B` / `#FFFBEB` / `#B45309` · danger `#EF4444` / `#FEF2F2` / `#B91C1C`. +- **Page chrome** (print/PDF only) — a 4.5pt red bar across the top edge, and a footer with a rule + above it, the horizontal logo left, "Seite X von Y" right in `#9CA3AF`. + +## Form language + +From the written style spec, and it applies to layout and diagrams as much as to imagery: + +- Flat and geometric. Sharp edges, clear planar division, generous whitespace. +- Depth only through restrained, flat shadows used to separate layers — one light source, one + direction, one softness. Never plastic or material-realistic. +- Rounded and organic shapes must not carry the composition. Corner radii stay small (0–4px); + `rounded-lg` everywhere is off-brand. +- Perspective, where used, resolves to a single consistent vanishing point. + +Explicitly ruled out: Corporate Memphis, humanoid illustration, glow and neon, rainbow gradients, +glossy 3D, AI-stock look, third-party logos. + +## Applying this to an Artifact + +`artifact-design` already defers to an existing design system — this file is that system, so its +tokens and patterns override the generic guidance there. What still applies from `artifact-design`: +build both themes at token level, give `body` an explicit background, keep wide content in its own +`overflow-x: auto` container. + +Work in this order: + +1. **Draft** — build the page from `references/tokens.css`. The Artifact CSP blocks every + external host, so fonts and the logo must be embedded; do not paste base64 by hand — + write `__ROOBERT_VF__` and `__LOGO_SVG__` placeholders instead. +2. **Brand check** — walk the draft through the "Before finishing" list below. For + anything the list does not settle (logo variant choice, red tints, icon sizing, + photography), consult `references/brand-rules.md`. Fix every failure before moving on. +3. **Inline assets** — run: + + ```bash + python3 ~/.claude/skills/mindtwo-branding/references/inline-assets.py + ``` + + It substitutes the font data URI and the inline logo in place and reports the resulting + size. The script looks for the `mindtwo` repo in common project directories; set + `MINDTWO_REPO` to its path if it lives elsewhere. The `@font-face` block to pair with + the placeholder is in `tokens.css`. +4. **Deliver** — hand over or publish only after steps 2 and 3 have passed. + +For a dark deliverable, the ground is `#121212` — mindtwo Black, not a neutral near-black — and the +accent lifts to `#FF6470` so it holds contrast. Both are CI values; do not invent a lighter red. + +## Editing existing content + +When editing an existing deliverable, fix brand violations only in the passages the edit +actually touches. Violations noticed elsewhere are reported to the user — location plus +the rule broken — but left unchanged unless the user asks. A brand pass over the whole +document is its own task, never a side effect of an edit. + +## Before finishing + +- [ ] Brand name is lowercase "mindtwo" in every occurrence, headings and sentence starts included +- [ ] Client-facing copy uses Sie; Du appears only in employer-branding content; never mixed +- [ ] Tagline, if present, reads exactly "Build. Accelerate. Scale." +- [ ] Red is accent-only (~10%) — no red surface larger than an eyebrow, rule, link, or button +- [ ] Ground is #FFFFFF or #121212; no #000 grounds, no neutrals outside the documented grey ramp +- [ ] All text is Roobert (or the sanctioned fallback); headings at 600; no bold body text +- [ ] No justified, right-aligned, or all-caps text anywhere +- [ ] Logo unmodified; clear space ≥ the wordmark's "m"; minimum height respected (50/78/32px) +- [ ] Corner radii ≤ 4px; no forbidden imagery styles (brand-rules.md "Forbidden") +- [ ] For edits: violations fixed only in touched passages; the rest listed, not changed diff --git a/skills/mindtwo-branding/references/brand-rules.md b/skills/mindtwo-branding/references/brand-rules.md new file mode 100644 index 0000000..c3a4da5 --- /dev/null +++ b/skills/mindtwo-branding/references/brand-rules.md @@ -0,0 +1,168 @@ +# mindtwo brand rules + +Extracted from `mindtwo_Brand-Guide-DE_v1_FINAL_200426.pdf` (31 pages). Page numbers in +parentheses. Act only on what is written here or in SKILL.md; if both are silent, choose +the most conservative option and say so. Never invent a brand rule. + +## Voice & Tone + +- Address the reader as *Sie* in client-facing copy. Write "Software, die Ihr Business + vorantreibt", not "Software, die dein Business vorantreibt" (pp. 2, 20, 22 — every + client-facing example in the guide uses Sie). +- Use *Du* only in employer-branding content (careers, benefits). Write "Dein + Arbeitsumfeld", "Bleibe fit und flexibel" as the careers examples do (pp. 22, 25). + Do not mix Sie and Du within one deliverable. +- Write the tagline exactly as "Build. Accelerate. Scale." — three words, a period after + each. Do not write "Build, Accelerate, Scale", do not translate it (pp. 2, 22, 27). + +Note: the guide's table of contents announces a "Kommunikation" chapter, but this version +contains none — the Sie/Du rules above are derived from the guide's own copy examples. +See Open questions. + +## Wording & Terminology + +- Write the brand name lowercase: "mindtwo". Never "Mindtwo", "MindTwo", or "MINDTWO" — + the first letter of the wordmark always stays lowercase (p. 12), and every occurrence in + the guide's running text is lowercase (pp. 2, 4, 30). +- Name the brand colours "mindtwo Red", "mindtwo Black", "mindtwo White" — brand name + lowercase, colour word capitalised (p. 14). +- Use the positioning line verbatim when introducing the agency: "Digitalagentur für + Software, die Ihr Business vorantreibt." (pp. 2, 22). +- Use the extended-logo tagline verbatim: "Digitalagentur im Herzen von Bonn" (p. 11). +- Write CTAs short and goal-first, as in the guide's examples: "Jetzt bewerben", + "Kontakt" (p. 22), "Mehr zu Benefits", "Zu Events", "Mehr dazu", "Zum Jobticket" + (p. 25). Do not write long descriptive CTAs ("Klicken Sie hier, um mehr über unsere + Benefits zu erfahren"). + +## Typography + +- Set all text in Roobert, a monolinear geometric sans serif (p. 18). +- Use only the documented cuts: Light, Regular, Semibold, Bold (p. 19). +- Do not set body text or longer passages in Bold; Bold is not for Fließtext (p. 20). +- Keep letter-spacing neutral — neither too tight nor too wide (p. 20). +- Keep line-height balanced — neither too small nor too large (p. 20). +- Set text left-aligned with a ragged right edge. Do not use justified text (Blocksatz); + do not use right-aligned ragged text (p. 20). +- Do not set headlines or longer texts in all caps (Versalien) (p. 20). +- When Roobert is technically unavailable — e-mails, newsletters, Google Docs, third-party + tools that cannot load webfonts — use Arial as the substitute (p. 21). The fallback + stack in `tokens.css` implements this. + +## Colour + +- mindtwo Red: HEX `#DE0639` · RGB 222/6/57 · CMYK 00/97/74/13 · + okLCH 0.5709/0.2275/20.4 · PMS 1925 C (p. 14). +- mindtwo Black: HEX `#121212` · RGB 18/18/18 · CMYK 60/40/40/100 (p. 14). +- mindtwo White: HEX `#FFFFFF` · RGB 255/255/255 · CMYK 0/0/0/0 (p. 14). +- Distribute colour by the 60:30:10 rule. Light scheme: 60% White / 30% Black / 10% Red. + Dark scheme: 60% Black / 30% White / 10% Red (p. 15). +- Treat 60:30:10 as a rough visual guideline, not an exact ratio — the guide states + flexibility is intended (p. 15). Red remains the 10% accent in both schemes. +- Derive red tints and shades only by lightening/darkening `#DE0639` or by reducing its + opacity over white or black (p. 16). Do not introduce any other red; the guide fixes no + hex values for the variants — its scale is explicitly exemplary ("beispielhaft") (p. 16). + +## Imagery & Logo + +### Logo variants and usage + +- Use the primary logo (horizontal) by default, whenever space allows (p. 7). +- Use the secondary logo (vertical) when space is limited or the primary logo does not + work well (p. 7). +- Use the standalone wordmark for limited space or reduced, minimalist applications — + e.g. clothing, stationery (p. 11). +- Use the standalone symbol exclusively in small formats where a full logo does not fit + (p. 11). +- Use the logo with the tagline "Digitalagentur im Herzen von Bonn" when introducing the + brand or adding context — e.g. brochures, social media (p. 11). + +### Clear space and minimum sizes + +- Keep clear space on all sides of the logo at least the width of the wordmark's letter + "m". Never undercut it (p. 8). +- Respect the minimum heights (p. 8): + - Primary logo (horizontal): 50 px digital / 5 mm print. + - Secondary logo (vertical): 78 px digital / 8 mm print. + - Symbol alone: 32 px digital / 5 mm print. + +### Colour variants + +- On black grounds: white wordmark ("mind" white, "two" red) with the red symbol (p. 9). +- On white grounds: black-and-red wordmark ("mind" black, "two" red) with the red symbol + (p. 9). +- On red grounds: the all-white logo — symbol and wordmark entirely white (p. 9). +- Use the monochrome black or white variants where a colour version cannot be used, e.g. + reduced or low-contrast environments (p. 10). + +### Logo don'ts + +- Do not rotate or tilt the logo, or place it at an angle (p. 12). +- Do not move, mirror, or re-orient the symbol relative to the wordmark (p. 12). +- Do not change the size ratio between symbol and wordmark (p. 12). +- Do not distort the logo; keep its proportions (p. 12). +- Do not change the wordmark's typeface (p. 12). +- Do not capitalise the wordmark's first letter — never "Mindtwo" in the logo (p. 12). + +### Icons + +- Use only the approved duotone icon set (Figma / Drive) (p. 24). +- Do not use the old icon version with the red hexagon (p. 25). +- Do not use unapproved icons (p. 25). +- Size icons between one and three lines of body text in height — no larger, no smaller + (p. 25). +- Use icons to support a statement or convey context; do not use them decoratively or in + excess (p. 25). System icons needed for basic UI function (e.g. carets on dropdowns) + are exempt (p. 25). + +### Graphics and form language + +- Build background elements from calm, geometric planes with clean edges and clear + division of area (p. 27). +- Keep depth minimal: subtle shading only (p. 27). Show dimensionality through restrained + shadows, never through materiality, textures, or strong realistic shading (p. 28). +- Large colour fields with a soft, flowing gradient are permitted (p. 27); keep gradients + subtle (p. 28). +- Use 2D or flat-3D graphics with clear lines, defined planes, and a reduced palette; + design each piece in either a light or a dark style, not both (p. 28). +- Use the historic key visual sparingly (p. 27). + +### Photography + +- Use bright, well-lit images with balanced, not-too-strong contrasts and slightly + reduced, harmonious colours (p. 30). +- Show authentic, inviting, un-staged situations with tidy, calm backgrounds (p. 30). + +## Forbidden + +- Shapes with rounded edges, flowing lines, or organic structures (p. 29). +- Reality-detached or obviously AI-generated graphics (p. 29). +- Generic, abstract graphics without a clear motif and relation to the topic (p. 29). +- Aggressive colour gradients and strong lighting effects (p. 29). +- Plastic-looking 3D graphics with realistic shading (p. 29). +- Illustrations or humanoid figures in comic style (Corporate Memphis) (p. 29). +- Justified text (Blocksatz) (p. 20). +- Right-aligned ragged text (p. 20). +- All-caps headlines or longer all-caps texts (p. 20). +- Roobert Bold for body text or longer passages (p. 20). +- The old red-hexagon icon style; unapproved icons; purely decorative icons (p. 25). +- In photos: unnatural effects, stickers, or image manipulation; under- or overexposed + or low-quality shots; unrealistic or heavily edited photos; staged or overly serious + scenes; busy or untidy motifs and backgrounds; overly abstract shots without a clear + motif or topical relation (p. 31). + +## Open questions + +- The table of contents (p. 4) lists chapters "Kommunikation", "Präsentation", and + "Social Media", but this version of the PDF contains no such pages. There is therefore + no explicit rule on address form (Sie/Du), tone, forbidden words, or sentence structure; + the Voice & Tone rules above are inferred from the guide's own copy examples only. +- The okLCH values for mindtwo Black (0/0/0) and mindtwo White (1/0/0) on p. 14 describe + pure black/white, not `#121212`/`#FFFFFF` — they look like placeholders. Treat the hex + values as authoritative. +- The guide prints the colour model as "CYMK" (pp. 14, 16); assumed to mean CMYK in the + labelled order. +- The red-variant scale (p. 16) defines no hex values. The production variants + `#9C182E` / `#FF6470` referenced in SKILL.md come from the mindtwo repo, not from this + PDF. +- SKILL.md calls the 60/30/10 rule "binding", while the guide explicitly calls it a rough + guideline that need not be met exactly (p. 15). diff --git a/skills/mindtwo-branding/references/inline-assets.py b/skills/mindtwo-branding/references/inline-assets.py new file mode 100644 index 0000000..a1a7508 --- /dev/null +++ b/skills/mindtwo-branding/references/inline-assets.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +"""Inline mindtwo brand assets into an HTML file for Artifact publishing. + +The Artifact CSP blocks every external host, so the Roobert font and the logo +have to be embedded. Emitting ~120 KB of base64 by hand is wasteful and +error-prone, so write the page with placeholders and let this substitute them. + + python3 inline-assets.py path/to/page.html + +Placeholders it replaces, wherever they appear in the file: + + __ROOBERT_VF__ variable-font data URI (woff2, weight axis 300-900) + __ROOBERT_REGULAR__ static 400 data URI, if a variable font is not viable + __ROOBERT_SEMIBOLD__ static 600 data URI + __LOGO_SVG__ horizontal logo, wordmark switched to currentColor so it + works on both themes; the mark stays mindtwo Red + __LOGO_SVG_BRAND__ horizontal logo verbatim (white wordmark, red mark) — + for dark grounds only + +Running it twice is safe: placeholders are gone after the first pass, so the +second is a no-op. Substitution happens in place. +""" + +import base64 +import os +import pathlib +import sys + + +def find_brand_repo() -> pathlib.Path: + """Locate the mindtwo repo checkout. Set MINDTWO_REPO to override.""" + if env := os.environ.get("MINDTWO_REPO"): + return pathlib.Path(env).expanduser() + home = pathlib.Path.home() + candidates = [ + home / "Development/Projects/mindtwo", + home / "code/mindtwo", + home / "Projects/mindtwo", + ] + for candidate in candidates: + if candidate.is_dir(): + return candidate + return candidates[0] + + +BRAND_REPO = find_brand_repo() +FONT_DIR = BRAND_REPO / "resources/assets/fonts/roobert" +LOGO = BRAND_REPO / "resources/assets/images/mindtwo/logo-horizontal.svg" + +FONTS = { + "__ROOBERT_VF__": FONT_DIR / "RoobertVF.woff2", + "__ROOBERT_REGULAR__": FONT_DIR / "Roobert-Regular.woff2", + "__ROOBERT_SEMIBOLD__": FONT_DIR / "Roobert-SemiBold.woff2", +} + + +def font_data_uri(path: pathlib.Path) -> str: + encoded = base64.b64encode(path.read_bytes()).decode("ascii") + return f"data:font/woff2;base64,{encoded}" + + +def logo_svg(theme_aware: bool) -> str: + svg = LOGO.read_text(encoding="utf-8").strip() + if theme_aware: + # The wordmark paths are filled #fff; the mark is mindtwo Red and stays. + svg = svg.replace('fill="#fff"', 'fill="currentColor"') + return svg + + +def main() -> int: + if len(sys.argv) != 2: + print(__doc__) + return 2 + + target = pathlib.Path(sys.argv[1]) + if not target.is_file(): + print(f"error: {target} does not exist") + return 1 + + missing = [p for p in (LOGO, *FONTS.values()) if not p.is_file()] + if missing: + print( + "error: brand assets not found — is the mindtwo repo checked out?" + " (set MINDTWO_REPO to its path if it lives elsewhere)" + ) + for path in missing: + print(f" {path}") + return 1 + + html = target.read_text(encoding="utf-8") + before = len(html) + applied = [] + + for token, path in FONTS.items(): + if token in html: + html = html.replace(token, font_data_uri(path)) + applied.append(f"{token} → {path.name} ({path.stat().st_size / 1024:.0f} KB raw)") + + for token, theme_aware in (("__LOGO_SVG__", True), ("__LOGO_SVG_BRAND__", False)): + if token in html: + html = html.replace(token, logo_svg(theme_aware)) + applied.append(f"{token} → {LOGO.name}") + + if not applied: + print("no placeholders found — nothing to do") + return 0 + + target.write_text(html, encoding="utf-8") + + for line in applied: + print(f" {line}") + print(f"\n{target.name}: {before / 1024:.0f} KB → {len(html) / 1024:.0f} KB") + print("Artifact limit is 16 MB, so this is fine unless you embedded images too.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/skills/mindtwo-branding/references/tokens.css b/skills/mindtwo-branding/references/tokens.css new file mode 100644 index 0000000..1a7b118 --- /dev/null +++ b/skills/mindtwo-branding/references/tokens.css @@ -0,0 +1,233 @@ +/* ───────────────────────────────────────────────────────────────────────────── + mindtwo corporate identity — design tokens + Source of truth: mindtwo repo → resources/assets/css/mindtwo.css (@theme), + resources/views/global/pdf/markdown-document.blade.php, + resources/prompts/blog-featured-image.txt + + Paste the @font-face + :root blocks into the artifact, then run + references/inline-assets.py to replace __ROOBERT_VF__ with the font data URI. + ───────────────────────────────────────────────────────────────────────────── */ + +@font-face { + font-family: 'Roobert'; + src: url('__ROOBERT_VF__') format('woff2-variations'); + font-weight: 300 900; + font-style: normal; + font-display: swap; +} + +:root { + /* ── brand constants — identical in both themes ── */ + --m2-red: #de0639; + --m2-red-dark: #9c182e; + --m2-red-light: #ff6470; + --m2-black: #121212; + --m2-white: #ffffff; + + /* ── surfaces & ink (light) ── */ + --ground: #ffffff; + --surface: #f9fafb; + --surface-2: #f3f4f6; + --ink: #111827; + --ink-body: #374151; + --ink-muted: #6b7280; + --ink-faint: #9ca3af; + --rule: #e5e7eb; + --rule-strong: #d1d5db; + + /* ── accent — the 10% of 60/30/10 ── */ + --accent: var(--m2-red); + --accent-ink: #ffffff; + + /* ── semantic callouts ── */ + --note: #3b82f6; --note-bg: #eff6ff; --note-ink: #1d4ed8; + --tip: #10b981; --tip-bg: #ecfdf5; --tip-ink: #047857; + --caution: #f59e0b; --caution-bg: #fffbeb; --caution-ink: #b45309; + --danger: #ef4444; --danger-bg: #fef2f2; --danger-ink: #b91c1c; + + /* ── type ── */ + --font-brand: 'Roobert', Arial, 'Helvetica Neue', sans-serif; + --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace; + + /* Licence-safe fallback: use as --font-brand when Roobert cannot be embedded. + Arial is the substitute the Brand Guide mandates (p. 21). + --font-brand: Arial, 'Helvetica Neue', sans-serif; */ + + /* ── geometry — sharp, per the form language ── */ + --radius: 2px; + --radius-lg: 4px; + --rule-w: 1px; + --accent-bar: 3px; + + /* ── flat, single-light-source elevation ── */ + --shadow: 0 1px 2px rgba(18, 18, 18, .06), 0 8px 24px -18px rgba(18, 18, 18, .24); +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) { + --ground: #121212; + --surface: #1a1a1a; + --surface-2: #232323; + --ink: #ffffff; + --ink-body: #d1d5db; + --ink-muted: #9ca3af; + --ink-faint: #6b7280; + --rule: #2a2a2a; + --rule-strong: #3a3a3a; + + /* red lifts to the CI light variant so it holds contrast on #121212 */ + --accent: var(--m2-red-light); + --accent-ink: #121212; + + --note-bg: #12233d; --note-ink: #93b8fb; + --tip-bg: #0e2a20; --tip-ink: #6ee7b7; + --caution-bg: #2b2010; --caution-ink: #fcd34d; + --danger-bg: #2d1416; --danger-ink: #fca5a5; + + --shadow: 0 1px 2px rgba(0, 0, 0, .5), 0 8px 24px -18px rgba(0, 0, 0, .8); + } +} + +:root[data-theme="dark"] { + --ground: #121212; + --surface: #1a1a1a; + --surface-2: #232323; + --ink: #ffffff; + --ink-body: #d1d5db; + --ink-muted: #9ca3af; + --ink-faint: #6b7280; + --rule: #2a2a2a; + --rule-strong: #3a3a3a; + + --accent: var(--m2-red-light); + --accent-ink: #121212; + + --note-bg: #12233d; --note-ink: #93b8fb; + --tip-bg: #0e2a20; --tip-ink: #6ee7b7; + --caution-bg: #2b2010; --caution-ink: #fcd34d; + --danger-bg: #2d1416; --danger-ink: #fca5a5; + + --shadow: 0 1px 2px rgba(0, 0, 0, .5), 0 8px 24px -18px rgba(0, 0, 0, .8); +} + +/* ───────────────────────────────────────────────────────────────────────────── + Signature patterns, ported from the Markdown→PDF template. + Copy the ones the deliverable actually uses; delete the rest. + ───────────────────────────────────────────────────────────────────────────── */ + +body { + background: var(--ground); + color: var(--ink-body); + font-family: var(--font-brand); + line-height: 1.6; +} + +/* The primary red moment. Most pages need exactly one of these per section. */ +.eyebrow { + font-size: .75rem; + font-weight: 600; + letter-spacing: .1em; + text-transform: uppercase; + color: var(--accent); + padding-left: 8px; + border-left: var(--accent-bar) solid var(--accent); +} + +.doc-title { + font-weight: 600; + letter-spacing: -.03em; + line-height: 1.15; + color: var(--ink); + text-wrap: balance; +} + +h2 { + font-weight: 600; + letter-spacing: -.02em; + line-height: 1.25; + color: var(--ink); + padding-bottom: .4rem; + border-bottom: var(--rule-w) solid var(--rule); + text-wrap: balance; +} + +h3 { font-weight: 600; color: var(--ink); } + +a { color: var(--accent); text-decoration: none; } +a:hover { text-decoration: underline; } +:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } + +blockquote { + border-left: var(--accent-bar) solid var(--accent); + background: var(--surface); + padding: .75rem 1rem; + font-style: italic; +} + +code { + font-family: var(--font-mono); + font-size: .88em; + background: var(--surface-2); + border-radius: var(--radius); + padding: 1px 5px; +} + +pre { + background: #1a1a1a; + color: #e5e7eb; + padding: 1rem; + border-radius: var(--radius); + overflow-x: auto; +} +pre code { background: none; padding: 0; color: inherit; } + +.table-wrap { overflow-x: auto; } + +table { width: 100%; border-collapse: collapse; } +thead th { + background: var(--surface-2); + color: var(--ink); + font-weight: 600; + text-align: left; + padding: .5rem .65rem; + border-bottom: 2px solid var(--rule-strong); +} +tbody td { + padding: .4rem .65rem; + border-bottom: var(--rule-w) solid var(--rule); + color: var(--ink-body); + vertical-align: top; + font-variant-numeric: tabular-nums; +} +tbody tr:last-child td { border-bottom: none; } + +.callout { + border-left: var(--accent-bar) solid; + border-radius: var(--radius); + padding: .8rem 1rem; +} +.callout > .callout-title { + font-size: .8rem; + font-weight: 600; + letter-spacing: .08em; + text-transform: uppercase; + margin-bottom: .4rem; +} +.callout-note { border-color: var(--note); background: var(--note-bg); } +.callout-note > .callout-title { color: var(--note-ink); } +.callout-tip { border-color: var(--tip); background: var(--tip-bg); } +.callout-tip > .callout-title { color: var(--tip-ink); } +.callout-caution { border-color: var(--caution); background: var(--caution-bg); } +.callout-caution > .callout-title { color: var(--caution-ink); } +.callout-danger { border-color: var(--danger); background: var(--danger-bg); } +.callout-danger > .callout-title { color: var(--danger-ink); } + +/* Screen equivalent of the PDF's 4.5pt red top bar. */ +.brand-bar { + height: 4px; + background: var(--m2-red); +} + +@media (prefers-reduced-motion: reduce) { + * { animation-duration: .01ms !important; transition-duration: .01ms !important; } +}