diff --git a/api/app/templates/base.css b/api/app/templates/base.css index e2808b4..ebc0ae3 100644 --- a/api/app/templates/base.css +++ b/api/app/templates/base.css @@ -73,8 +73,11 @@ body.cv { .cv-entry-title { font-weight: 700; } .cv-dates { flex-shrink: 0; margin-right: 44pt; font-size: 9pt; color: #595959; white-space: nowrap; } .cv-bullets { margin: 0; padding: 0 0 0 36pt; list-style: none; } -.cv-bullets li { position: relative; margin: 0; } -.cv-bullets li::before { content: "•"; position: absolute; left: -18pt; font-family: Arial, "Liberation Sans", sans-serif; } +.cv-bullets li { margin: 0; } +/* The bullet sits in the line, hung into the list's indent, rather than positioned: WeasyPrint draws positioned + boxes after the page's other text, so a parser reading the PDF in order found every bullet after Skills. */ +.cv-bullets li::before { content: "•"; display: inline-block; width: 18pt; margin-left: -18pt; line-height: 1; + font-family: Arial, "Liberation Sans", sans-serif; } .cv-muted { font-size: 9pt; color: #595959; } /* ── Fit to page ────────────────────────────────────────────────────── */ diff --git a/api/tests/test_documents.py b/api/tests/test_documents.py index 0bed541..dbe17a4 100644 --- a/api/tests/test_documents.py +++ b/api/tests/test_documents.py @@ -583,6 +583,17 @@ def test_the_graduate_cv_is_one_page_in_the_designs_type_with_live_links(pdf_dir assert {"mailto:sam@example.com", "https://github.com/samokafor"} <= uris +@needs_weasyprint +def test_a_parser_reading_the_cv_in_order_finds_each_bullet_under_its_role(pdf_dir): + # A parser reads the PDF in the order it was drawn. A positioned bullet marker was drawn after the page's other + # text, so every experience bullet came after the Skills section, cut off from its role. + cv = agent._persona_to_cvdoc(GRADUATE) | {"seniority": "junior"} + text = " ".join(_weasy("cv", cv)[0].get_text().split()) + order = ["Software Engineering Intern", "Built a FastAPI service that ingests 40k", "Pantry Planner", + "Skills & Technical Proficiency"] + assert [text.index(s) for s in order] == sorted(text.index(s) for s in order) + + @needs_weasyprint def test_a_full_graduate_cv_fits_one_page(pdf_dir): # Everything the tailoring prompt allows a junior: a 3-sentence summary, three roles with 2 bullets of