"""Unit: the phase-93 page-head surface panel contract (task 03 — source pins). Owner direction (TODO.md L3): "Also the header and description of each page needs a background - the grid makes it hard to read." Every page's ``h1`` + description (the shell's standard ``.page-head`` frame) sits on a solid ``var(--surface)`` panel — the house card language — so the 44px background grid never fights the heading text. Browser behavior (computed ``background-color`` non-transparent on every head, the History flex row + 360px wrap unbroken, the monochrome theme graying the panel) is E2E-gated by ``tests/e2e/ test_theme_semantic_completion.py`` (task 04) and the existing header/nav/responsive suites; here we pin the source-level contract (house pattern: ``tests/unit/test_background_no_motion.py`` parses ``styles.css`` rules): * the shared ``.page-head`` rule declares the panel — a NON-transparent ``background`` built from ``var(--surface)`` (no color literal of any kind, no blur — the phase-08 perf anchor), the 1px ``var(--line)`` border, the house card radius, and card-rhythm padding; * the ``#view-history`` page-head keeps its SCOPED flex row (padding lives on the flex container — the base rule — never on the children), and the mobile ``.page-head-row { flex-wrap: wrap; }`` survives; * every shell view that carries a ``.page-head`` in the shell markup is covered by the ONE rule (six views; ``#view-chat`` carries no ``.page-head`` — its head is the navbar, audited), and ``doc-edit.html`` keeps its ``.page-head``; * the standalone pages: the shared page's head (``h1#shared-title`` + the lede) is wrapped in the same ``.page-head`` class, while the two heads that already sit inside a surfaced card are deliberately UNTOUCHED (login's ``.login-card`` — surface card; document viewer's ``.doc-titlebar`` inside the sticky surface ``.doc-header``). """ from __future__ import annotations import re from pathlib import Path FRONTEND = Path(__file__).resolve().parents[2] / "frontend" STYLES_CSS = FRONTEND / "assets" / "styles.css" INDEX_HTML = FRONTEND / "index.html" SHARED_HTML = FRONTEND / "shared.html" DOC_EDIT_HTML = FRONTEND / "doc-edit.html" LOGIN_HTML = FRONTEND / "login.html" DOCUMENT_HTML = FRONTEND / "document.html" # The six shell views whose h1 + description sit in a .page-head # (#view-chat carries none — its head is the navbar; audited). SHELL_VIEWS_WITH_PAGE_HEAD = ( "view-tuning", "view-rag", "view-git-sources", "view-history", "view-tokens", "view-theme", ) def _css() -> str: return STYLES_CSS.read_text(encoding="utf-8") def _css_no_comments() -> str: return re.sub(r"/\*[\s\S]*?\*/", "", _css()) def _find_rule(css: str, selector: str) -> re.Match[str] | None: """The first top-level ``selector { ... }`` rule (comments stripped by the caller when prose must not interfere).""" return re.search(r"(?m)^" + re.escape(selector) + r"\s*\{([\s\S]*?)\n\}", css) def _rule_block(css: str, selector: str) -> str: rule = _find_rule(css, selector) assert rule, f"styles.css must define a {selector} rule" return rule.group(1) def _view_section(body: str, view_id: str) -> str: """The view section slice — from its opening tag to the next sibling view (or ````). A first-```` slice would cut short: the views nest gate sections (``
``) INSIDE, and the Git-sources / Theme ``.page-head`` sits after the first nested close.""" start = body.find(f'
", start)) if e != -1 ] assert boundaries, "the shell must have a closing " return body[start : min(boundaries)] # -------------------------------------------------------------------------- # The shared .page-head rule — the surface panel # -------------------------------------------------------------------------- def test_page_head_rule_is_the_surface_panel() -> None: """The one shared rule declares the panel: a non-transparent background from ``var(--surface)`` (itself tab-controlled — a monochrome theme grays the head automatically), the 1px ``var(--line)`` border, the house card radius, and card-rhythm padding (the phase-93 panel: 1rem block / 1.25rem inline).""" block = _rule_block(_css_no_comments(), ".page-head") assert "background: var(--surface)" in block, ( "the .page-head panel must fill with var(--surface) — solid, " "never transparent, never a literal" ) assert "border: 1px solid var(--line)" in block, ( "the panel must carry the house 1px --line border" ) assert "border-radius: var(--radius)" in block, ( "the panel must use the house card radius" ) assert re.search(r"padding:\s*1rem\s+1\.25rem", block), ( "the panel must carry the card-rhythm padding (1rem 1.25rem)" ) def test_page_head_rule_has_no_color_literal_and_no_blur() -> None: """Phase-92 invariant + phase-08 perf anchor: the panel rule introduces NO new color literal (hex / rgb / hsl / color-mix — ``var(--…)`` only) and no filter/blur.""" block = _rule_block(_css_no_comments(), ".page-head") assert not re.search(r"#[0-9a-fA-F]{3,8}\b", block), ( "no hex color literal in the .page-head panel (phase-92 invariant)" ) for func in ("rgb(", "hsl(", "color-mix("): assert func not in block, f"no {func}… literal in the .page-head panel" assert "filter" not in block and "blur" not in block, ( "no filter/blur in the .page-head panel (phase-08 perf anchor)" ) def test_page_head_background_is_solid_not_translucent() -> None: """The panel is SOLID — the assumption the phase locked (not translucent, not a full-bleed band, no blur): the background declaration names exactly the surface variable, nothing mixed.""" block = _rule_block(_css_no_comments(), ".page-head") backgrounds = re.findall(r"(?m)^\s*background(?:-color)?:\s*([^;]+);", block) assert backgrounds == ["var(--surface)"], ( f"the .page-head background must be exactly var(--surface), " f"got {backgrounds}" ) # -------------------------------------------------------------------------- # Layout safety — the History flex row and the mobile wrap # -------------------------------------------------------------------------- def test_history_page_head_keeps_its_scoped_flex_row() -> None: """The ``#view-history .page-head`` flex row (title left, refresh pill right — phase 77) survives the panel: the scoped rule keeps its flex declarations and adds NO padding of its own (the task-03 rule — padding on the flex container, i.e. the base ``.page-head`` rule, never on the children, so space-between + align stay intact inside the padded box).""" scoped = _rule_block(_css_no_comments(), "#view-history .page-head") for decl in ( "display: flex", "flex-wrap: wrap", "align-items: flex-start", "justify-content: space-between", ): assert decl in scoped, f"#view-history .page-head must keep {decl!r}" assert not re.search(r"(?m)^\s*padding\b", scoped), ( "the scoped History rule must not add its own padding — the " "base .page-head rule (the flex container) carries it" ) def test_mobile_page_head_row_wrap_survives() -> None: """≤640px: ``.page-head-row { flex-wrap: wrap; }`` (the RAG head's Sync pill drops below the title at full width) still exists in the mobile block — the wrap keeps working INSIDE the panel.""" mobile = re.search(r"@media \(max-width: 640px\) \{([\s\S]*?)\n\}\n", _css()) assert mobile, "the mobile media query must exist" assert ".page-head-row { flex-wrap: wrap; }" in mobile.group(1), ( "the mobile .page-head-row wrap must survive the panel" ) # -------------------------------------------------------------------------- # Coverage — every head that sits on the grid gets the panel # -------------------------------------------------------------------------- def test_every_shell_view_with_a_page_head_is_covered() -> None: """The ONE rule covers every shell view that carries the class: all six do (their ``class="page-head"`` div is static markup in the shell); #view-chat carries NO .page-head (its head is the navbar — audited, untouched).""" body = INDEX_HTML.read_text(encoding="utf-8") for view_id in SHELL_VIEWS_WITH_PAGE_HEAD: assert 'class="page-head"' in _view_section(body, view_id), ( f"#{view_id} must keep its .page-head (the shared rule panels it)" ) assert 'class="page-head"' not in _view_section(body, "view-chat"), ( "#view-chat carries no .page-head (its head is the navbar)" ) def test_doc_edit_page_head_is_covered() -> None: """doc-edit.html's head already IS a .page-head (h1 'Edit doc' + the .page-sub lede) — the shared rule panels it with no markup change.""" html = DOC_EDIT_HTML.read_text(encoding="utf-8") head = re.search( r'
\s*

Edit doc

[\s\S]*?class="page-sub"', html, ) assert head, "doc-edit.html must keep its .page-head (h1 + page-sub)" def test_shared_page_head_is_wrapped_in_page_head() -> None: """The shared page's head (``h1#shared-title`` + the read-only lede) was a direct child of the grid-exposed ``.shared-shell`` — it is now wrapped in the same ``.page-head`` class, so the shared rule panels it (the h1 keeps the ``.page-head h1`` size per the ``#shared-title`` rule).""" html = SHARED_HTML.read_text(encoding="utf-8") wrapped = re.search( r'
\s*' r"

Shared conversation

\s*" r'

Shared via Brain of Reese — read-only\.

\s*' r"
", html, ) assert wrapped, ( "shared.html must wrap the h1 + lede in a .page-head div" ) # -------------------------------------------------------------------------- # Deliberate skips — heads already inside a surfaced card # -------------------------------------------------------------------------- def test_login_head_is_already_carded_and_untouched() -> None: """login.html: h1#login-title lives inside section.login-card, which is ALREADY the surface card (var(--surface) fill + border + radius + shadow) — the TODO targets grid-exposed text, so the login head gets no double panel.""" html = LOGIN_HTML.read_text(encoding="utf-8") card = re.search( r'