diff --git a/travel-guide/README.md b/travel-guide/README.md
index 2e314b7..7ab2387 100644
--- a/travel-guide/README.md
+++ b/travel-guide/README.md
@@ -6,7 +6,7 @@ Turn a destination, a real traveler, and a few constraints into a considered tra
Most itinerary tools optimize for coverage. This skill helps an agent design for fit: the pace, people, budget, interests, energy, and small details that make a trip feel like it belongs to the travelers.
-It can produce a print-ready HTML dossier for PDF conversion, a responsive companion page, or both. The visual system is editorial by default: a darkened photographic cover with a route journey line, ghost section numbers, a color-coded day strip, pace and budget meters, and a unified warm photo grade across anchor photos. It keeps current logistics and recommendations tied to sources, and it can create a sanitized edition for sharing without exposing exact dates, lodging, booking identifiers, or private notes.
+It can produce a print-ready HTML dossier for PDF conversion, a responsive companion page, or both. The visual system is editorial by default: a darkened photographic cover with a route journey line, ghost section numbers, a color-coded day strip, pace and budget meters, a unified warm photo grade across anchor photos, and a bottom-of-page footer on each section that carries a field note, a next-section line, and a ghost route mark. It keeps current logistics and recommendations tied to sources, and it can create a sanitized edition for sharing without exposing exact dates, lodging, booking identifiers, or private notes.
## What You Get
diff --git a/travel-guide/SKILL.md b/travel-guide/SKILL.md
index eff98df..dfc5423 100644
--- a/travel-guide/SKILL.md
+++ b/travel-guide/SKILL.md
@@ -192,8 +192,12 @@ The visual default is a dark photographic cover with a route journey line, warm
gold eyebrow, white headline, restrained red accent, generous white content
pages, ghost section numbers, a color-coded day strip right after the brief,
pace and budget meters, compact cards, a unified warm photo grade on anchor
-images, and readable tables. Preserve contrast and selectable text. Do not let
-decoration hide uncertainty or practical caveats.
+images, readable tables, and a bottom-of-page footer per section: a content-
+derived field note (failure mode, plan B, recheck item, or skip reason) when
+one exists, a next-section line, and a ghost route mark. Preserve contrast and
+selectable text. Do not let decoration hide uncertainty or practical caveats.
+The footer is informational, never a schedule: it repeats model content in one
+line, it does not invent new plans.
## Exit criteria
diff --git a/travel-guide/references/editorial-structure.md b/travel-guide/references/editorial-structure.md
index 922b50c..0c84cde 100644
--- a/travel-guide/references/editorial-structure.md
+++ b/travel-guide/references/editorial-structure.md
@@ -90,6 +90,10 @@ The default visual language is editorial rather than app-like:
- pace and budget meters in the brief when the trip model supplies them;
- a unified warm photo grade on anchor images so mixed-source photos read as
one editorial set;
+- a bottom-of-page footer per section: a content-derived field note (the first
+ anchor's failure mode, the first day's alternative, the practical recheck
+ item, or the first skip reason) when one exists, a next-section line, and a
+ ghost route mark;
- dark table headers with clear column labels;
- short captions and visible image credits.
@@ -97,7 +101,10 @@ Use images to establish place and texture, not to imply that an image proves a
recommendation. Keep body text selectable and readable in grayscale or with
high-contrast settings. Every meaningful image needs useful alternative text.
The day strip is a glanceable overview, not a schedule: it must never invent a
-timed plan that the day cards do not support.
+timed plan that the day cards do not support. The section footer is the same
+kind of restraint: it repeats one line already in the model rather than adding
+new recommendations, and a section with nothing worth saying simply omits the
+field note.
## Companion web page
diff --git a/travel-guide/references/pdf-rendering.md b/travel-guide/references/pdf-rendering.md
index a15be5e..4b00636 100644
--- a/travel-guide/references/pdf-rendering.md
+++ b/travel-guide/references/pdf-rendering.md
@@ -67,6 +67,10 @@ Before delivery, verify all of the following:
- the day strip ("trip at a glance") shows one card per day with legible kind
colors, and the meters render when pace or budget are supplied;
- ghost section numbers do not collide with content;
+- each section footer sits at the bottom of its page without colliding with
+ content; the field note repeats a model line (failure mode, alternative,
+ recheck, or skip reason) and the next-section line matches the section that
+ actually follows;
- no page is blank, clipped, or unexpectedly split;
- title, tables, captions, and source URLs are readable;
- contrast works on the dark cover and in grayscale content pages;
diff --git a/travel-guide/scripts/render-travel-guide.py b/travel-guide/scripts/render-travel-guide.py
index 3996695..199305c 100755
--- a/travel-guide/scripts/render-travel-guide.py
+++ b/travel-guide/scripts/render-travel-guide.py
@@ -148,6 +148,70 @@ def render_meters(brief):
return '
%s
' % "".join(parts)
+SECTION_ORDER = ["brief", "glance", "anchors", "days", "special", "skip", "practical", "sources"]
+SECTION_HEADINGS = {
+ "brief": ("The brief", "Why this trip, now?"),
+ "glance": ("Trip at a glance", "The whole trip, one glance."),
+ "anchors": ("The anchors", "Protect the good parts."),
+ "days": ("Day architecture", "Enough shape to wander."),
+ "special": ("Make it special", "Make it special."),
+ "skip": ("A useful no", "Skip this."),
+ "practical": ("Field notes", "Keep the friction small."),
+ "sources": ("Evidence and freshness", "Sources."),
+}
+
+
+def field_note(section, brief):
+ """One content-derived line for the section footer; None when nothing fits."""
+ if section == "anchors":
+ first = next((a for a in brief.get("anchors", []) if isinstance(a, dict)), None)
+ if first and first.get("failure_mode"):
+ return ("If it goes wrong", first["failure_mode"])
+ if section == "days":
+ first = next((d for d in brief.get("days", []) if isinstance(d, dict)), None)
+ if first and first.get("alternative"):
+ return ("Plan B", first["alternative"])
+ if section == "practical":
+ for item in brief.get("practical", []):
+ if isinstance(item, dict) and "recheck" in str(item.get("label", "")).lower() and item.get("value"):
+ return ("Recheck before departure", item["value"])
+ if section == "skip":
+ first = next((s for s in brief.get("skip", []) if isinstance(s, dict)), None)
+ if first and first.get("reason"):
+ return ("Why we skip it", first["reason"])
+ return None
+
+
+def section_footer(section, brief):
+ """Bottom-of-page footer: field note, next-section line, and a ghost mark."""
+ note = field_note(section, brief)
+ note_html = ""
+ if note:
+ note_html = '%s%s' % (
+ esc(note[0]), esc(note[1]))
+ index = SECTION_ORDER.index(section)
+ next_html = ""
+ if index < len(SECTION_ORDER) - 1:
+ next_name = SECTION_ORDER[index + 1]
+ kicker, heading = SECTION_HEADINGS[next_name]
+ num = "%02d" % (index + 2)
+ next_html = ('Next: %s — %s'
+ '%s') % (esc(kicker), esc(heading), num)
+ else:
+ next_html = 'End of dossier'
+ mark = render_mark()
+ watermark = '