/* ═══════════════════════════════════════════════════════════════════════
   TRIPS · Concept C
   Loaded after design-v2-app.css and profile-c.css.

   Gated on `body.tv-on`, set by show() for the two trip views only. Every
   rule below is either prefixed with that class or confined to the `.tv-`
   namespace, so nothing here can reach another screen — the same discipline
   profile-c.css uses.

   THE C-6 TRAP. A `var(--dv2-*)` used on an element outside the token host
   voids the entire declaration it appears in, silently. The tokens live on
   `body.dv2-app`, which show() now sets for Trips, so descendants inherit
   them. Anything that renders in a portal outside <body>'s tree would not —
   there is nothing like that here, but that is why the gate is the body
   class and not `#view-trips`.

   The base standard is the ENTITY TILE (set Aug 2026, see profile-c.css):
   every entity gets its own discrete rounded tab, and the container behind
   those tabs is transparent. A trip, a traveller, a document, a readiness
   item — each is a tab. Never a flat row separated only by a divider.
   ═══════════════════════════════════════════════════════════════════════ */

body.tv-on {
  /* Trips reuses Profile's tile tokens rather than defining a second set —
     two token sets for one visual standard is how they drift apart. */
  --tv-tile-bg: rgba(255,255,255,0.72);
  --tv-tile-bd: rgba(20,16,38,0.07);
  --tv-shadow: 0 1px 3px rgba(20,20,40,0.05);
  --tv-rad: 16px;
  /* A TOKEN THAT WAS NEVER DEFINED IS A LITERAL IN DISGUISE.
     Three rules here asked for `--dv2-g-16-bg` and nothing anywhere ever set
     it, so all three quietly took their fallback — white — in BOTH themes.
     That is why the selected year tab was white text on a near-white pill in
     dark mode, and why every Travel sheet came up as a white slab over a black
     app. These two are real, and they are defined for both themes. */
  --tv-sheet-bg: rgba(255,255,255,0.86);
  --tv-ink-on-dark: #ffffff;
}
html[data-theme="dark"] body.tv-on {
  --tv-tile-bg: rgba(255,255,255,0.07);
  --tv-tile-bd: rgba(255,255,255,0.12);
  --tv-shadow: 0 1px 3px rgba(0,0,0,0.35);
  --tv-sheet-bg: #16182099;
  /* In dark the "selected" pill is a LIGHT fill, so the text on it has to be
     dark. White on white was the bug. */
  --tv-ink-on-dark: #14121F;
}
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) body.tv-on {
    --tv-tile-bg: rgba(255,255,255,0.07);
    --tv-tile-bd: rgba(255,255,255,0.12);
    --tv-shadow: 0 1px 3px rgba(0,0,0,0.35);
    --tv-sheet-bg: #16182099;
    --tv-ink-on-dark: #14121F;
  }
}

/* ── The ground ─────────────────────────────────────────────────────────
   style.css paints #view-trips / #view-trip on the old flat surface. The
   aurora comes from the tokens now, so those fills have to stand down or
   they sit on top of it as an opaque slab — the same mistake #shops-box
   made in Profile. */
body.tv-on #view-trips,
body.tv-on #view-trip,
body.tv-on #trip-list,
body.tv-on #list {
  background: transparent;
}

body.tv-on {
  background: var(--dv2-bg-grad, #F4F2FA);
  background-attachment: fixed;
  color: var(--dv2-text-primary);
}

/* ── Headers ────────────────────────────────────────────────────────────
   .sub-head / .topbar are the legacy chrome. Glass, matching the rest of
   the app, rather than the old solid bar. */
body.tv-on .sub-head.glass,
body.tv-on #view-trip .topbar.glass {
  background: var(--dv2-g-07-bg, rgba(255,255,255,0.5));
  border-bottom: 1px solid var(--dv2-g-07-bd, rgba(255,255,255,0.75));
  backdrop-filter: saturate(160%) blur(18px);
  -webkit-backdrop-filter: saturate(160%) blur(18px);
  box-shadow: none;
}
/* b232 · R9 — Travel's own title (`.sub-head h1`) is SPLIT off here. It takes
   the canon 28/800/-.02em from the end of style.css and keeps only its colour.
   The TRIP screen's title is a different element on a different screen and is
   left exactly as it was. */
body.tv-on .sub-head h1 {
  color: var(--dv2-text-primary);
}
body.tv-on #view-trip .title-wrap h1 {
  color: var(--dv2-text-primary);
  font-weight: 700;
  letter-spacing: -0.02em;
}
body.tv-on #view-trip .title-wrap .sub,
body.tv-on .sub-head .sub { color: var(--dv2-text-sub); }

/* ── b232 · SECTION_CHROME R1 — the inset, and why Travel escaped it ─────────
   Travel was never in `verify_chrome.py`'s SECTIONS list, so R1 had never
   been asserted against it once. It is the FIFTH screen to carry the same
   fault Garage, Shop, Home and Health each closed with the same one-line
   patch — but by a different mechanism: `.sub-head` is not a bare
   `.topbar-row`, it pays its own `var(--pad)` (20px) horizontal padding and
   cancels it again with a negative margin. 20px against a required 16, and
   out of R1's ±2 tolerance either way.

   The margin stays at -20px on purpose: it is what pulls the glass out to the
   viewport edge. Only the padding moves, which is what the inset actually is.
   Both appearance states — an inset is not a colour. */
body.tv-on #view-trips .sub-head,
body.tv-on #view-tripmap .sub-head {
  /* R1 · 16px, AND THE ARITHMETIC THIS MISSED THE FIRST TIME.
     `.sub-head` carries `margin: 0 calc(var(--pad) * -1)` so the glass reaches
     the screen edge. b232 set the padding to a flat 16px, which is the inset
     measured from the ELEMENT — but the element already starts 20px outside
     the container, so the first control landed at 16 - 20 = -4px, four pixels
     off the left of the screen. verify_chrome has reported `left: -4` on every
     run since.
     The padding has to clear the negative margin before it can inset anything,
     so it is that margin plus the 16px R1 actually asks for. Both Travel
     screens draw this header; only one of them was patched. */
  padding-left: calc(var(--pad) + 16px);
  padding-right: calc(var(--pad) + 16px);
}
/* The trailing group R1 asks for. `.sub-head` is a flex row with `gap:12px`
   and `h1 { flex:1 }`; three bare buttons made it a four-region row. `flex:
   none` so the group is the width of its buttons and the title keeps the
   slack. The 8px gap is Pets' (`.pv-top-side`), not the header's 12. */
body.tv-on #view-trips .tv-top-side {
  display: flex; align-items: center; gap: 8px; flex: none;
}
body.tv-on #view-trips .tv-top-side.end { justify-content: flex-end; }

body.tv-on .back-btn,
body.tv-on .icon-btn,
body.tv-on .nav-icon { color: var(--dv2-text-primary); }

/* ── Section headings ───────────────────────────────────────────────────
   13 raw <h2>/<h3> in the Trips markup, all inheriting whatever style.css
   last said. One treatment, matching Profile's domain labels. */
body.tv-on .sheet h2,
body.tv-on .sheet-head h2 {
  font-size: 19px; font-weight: 700; letter-spacing: -0.02em;
  color: var(--dv2-text-primary);
}
body.tv-on .sheet h3,
body.tv-on .tv-sec {
  font-size: 11px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--dv2-text-sub);
  margin: 18px 2px 8px;
}

/* ── THE ENTITY TILE ────────────────────────────────────────────────────
   One primitive. New components reach for `.tv-tile` rather than inventing
   a row style. */
body.tv-on .tv-tile {
  display: block;
  background: var(--tv-tile-bg);
  border: 1px solid var(--tv-tile-bd);
  border-radius: var(--tv-rad);
  padding: 13px 14px;
  margin: 0 0 9px;
  box-shadow: var(--tv-shadow);
  width: 100%;
  text-align: left;
  color: var(--dv2-text-primary);
  font-family: inherit;
}
body.tv-on .tv-tile:last-child { margin-bottom: 0; }
body.tv-on button.tv-tile:active { transform: scale(.985); }
@media (prefers-reduced-motion: reduce) {
  body.tv-on button.tv-tile:active { transform: none; }
}

/* The row inside a tile. Kept separate from the frame for the same reason
   .pc-mem-in is: a tile is a frame, not a layout. */
body.tv-on .tv-row { display: flex; align-items: center; gap: 11px; }
body.tv-on .tv-grow { flex: 1; min-width: 0; }
body.tv-on .tv-t { font-size: 15px; font-weight: 650; letter-spacing: -0.01em; }
body.tv-on .tv-s { font-size: 12.5px; color: var(--dv2-text-sub); margin-top: 1px; }
body.tv-on .tv-v { font-size: 13px; color: var(--dv2-text-sub); font-weight: 550; }

/* ── Status pills ───────────────────────────────────────────────────────
   Four states, and the fourth is the one that was missing: UNKNOWN. A
   traveller with no passport on file used to render no badge at all, which
   reads as approval. */
body.tv-on .tv-pill {
  font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: 100px;
  white-space: nowrap; letter-spacing: 0.01em;
}
body.tv-on .tv-pill.good { color: #16704A; background: rgba(22,112,74,0.11); }
body.tv-on .tv-pill.warn { color: #A25C00; background: rgba(162,92,0,0.12); }
body.tv-on .tv-pill.bad  { color: #B3312A; background: rgba(179,49,42,0.10); }
body.tv-on .tv-pill.info { color: var(--dv2-link, #5b4fe0); background: rgba(91,79,224,0.10); }
body.tv-on .tv-pill.unknown {
  color: var(--dv2-text-sub); background: transparent;
  border: 1px dashed var(--tv-tile-bd);
}
html[data-theme="dark"] body.tv-on .tv-pill.good { color: #5DD48F; background: rgba(93,212,143,0.14); }
html[data-theme="dark"] body.tv-on .tv-pill.warn { color: #E5A44A; background: rgba(229,164,74,0.15); }
html[data-theme="dark"] body.tv-on .tv-pill.bad  { color: #FF8A80; background: rgba(255,138,128,0.13); }
html[data-theme="dark"] body.tv-on .tv-pill.info { color: #9B85FF; background: rgba(155,133,255,0.15); }

/* ── Line icons ─────────────────────────────────────────────────────────
   One icon system. .dv2-lineic already carries the stroke properties and
   deliberately no size, so callers own that — a glyph emitted without a
   size rendered a 290px row in Profile once. */
body.tv-on .tv-ic {
  width: 21px; height: 21px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
}
body.tv-on .tv-ic-sm { width: 17px; height: 17px; }

/* ── Sheets ─────────────────────────────────────────────────────────────
   The trip sheets are the old .sheet.glass. Bring them onto the same glass
   as everything else, and make their menus tiles. */
body.tv-on .sheet.glass {
  background: var(--tv-sheet-bg);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  backdrop-filter: blur(22px) saturate(180%);
  border-top: 1px solid var(--tv-tile-bd);
  color: var(--dv2-text-primary);
}
body.tv-on .sheet.glass .sheet-head h2,
body.tv-on .sheet.glass .pe-title,
body.tv-on .sheet.glass #trip-actions-title { color: var(--dv2-text-primary); }
body.tv-on .sheet.glass .settings-txt b { color: var(--dv2-text-primary); }
body.tv-on .sheet.glass .settings-txt small { color: var(--dv2-text-sub); }
body.tv-on .sheet.glass .settings-chev { color: var(--dv2-text-muted); }
body.tv-on .settings-menu {
  background: transparent;      /* container behind the tabs stands down */
  border: 0;
  border-radius: 0;
  overflow: visible;
}
body.tv-on .settings-menu .settings-row {
  background: var(--tv-tile-bg);
  border: 1px solid var(--tv-tile-bd);
  border-radius: 14px;
  box-shadow: var(--tv-shadow);
  margin-bottom: 8px;
  color: var(--dv2-text-primary);
}
body.tv-on .settings-menu .settings-row:last-child { margin-bottom: 0; }
/* The hairline that used to separate rows inside the filled box. Tiles carry
   their own edge, so this would draw a second line on top of one. */
body.tv-on .settings-menu .settings-row + .settings-row { border-top: 0; }
body.tv-on .settings-row small { color: var(--dv2-text-sub); }
body.tv-on .settings-row.danger b { color: #B3312A; }
html[data-theme="dark"] body.tv-on .settings-row.danger b { color: #FF8A80; }

/* ── Fields ─────────────────────────────────────────────────────────────*/
body.tv-on .field input[type="text"],
body.tv-on .field input[type="date"],
body.tv-on .field select {
  background: var(--tv-tile-bg);
  border: 1px solid var(--tv-tile-bd);
  border-radius: 12px;
  color: var(--dv2-text-primary);
}
body.tv-on .field > span { color: var(--dv2-text-sub); }
body.tv-on .field .opt { color: var(--dv2-text-muted); }
body.tv-on .hint, body.tv-on .tp-lede { color: var(--dv2-text-sub); }

/* ── Buttons ────────────────────────────────────────────────────────────*/
body.tv-on .btn.primary {
  background: var(--dv2-link, #5b4fe0); color: #fff; border: 0;
  border-radius: 12px; font-weight: 650;
}
body.tv-on .btn:not(.primary):not(.danger):not(.danger-btn) {
  background: transparent; color: var(--dv2-text-primary);
  border: 1px solid var(--tv-tile-bd); border-radius: 12px;
}
body.tv-on .chip {
  background: var(--tv-tile-bg); border: 1px solid var(--tv-tile-bd);
  border-radius: 100px; color: var(--dv2-text-primary);
}

/* ── The trip cards on the index ────────────────────────────────────────
   Each trip is an entity, so each is a tab. */
body.tv-on .trip-card {
  background: var(--tv-tile-bg);
  border: 1px solid var(--tv-tile-bd);
  border-radius: var(--tv-rad);
  box-shadow: var(--tv-shadow);
  color: var(--dv2-text-primary);
}
body.tv-on .trip-card h3 { color: var(--dv2-text-primary); }
body.tv-on .tc2-when, body.tv-on .tc2-dates, body.tv-on .tc-meta {
  color: var(--dv2-text-sub);
}

/* ── Legacy furniture that has no place here ────────────────────────────
   HIDE, NEVER DELETE. app.js is one top-level IIFE: a non-optional
   dereference of a removed element throws at script-eval and bricks the
   whole app, so anything retired is switched off in CSS and left in the
   DOM. This is the standing rule, and it has been paid for once already. */
/* The DEAD ones only. #unlock-row holds the "Edit details" button, which is
   the sole way into edit mode on Essential information, and #parent-tools
   holds the two reset actions — both still do real work and are restyled
   below rather than retired. Sweeping the whole PIN-era zone away would have
   taken them with it. */
body.tv-on #trip-pin-row,
body.tv-on #t-pin,
body.tv-on #f-pin,
body.tv-on #btn-lock,
body.tv-on #del-trip-pin-input { display: none !important; }

/* "Parents" was the PIN system's word for it. The actions survive; the
   framing goes, because there is no parent mode any more — there is an admin,
   and the server has enforced that for some time. */
body.tv-on #parent-tools { border-top: 1px solid var(--dv2-divider, var(--tv-tile-bd)); padding-top: 14px; }
body.tv-on #parent-tools h3::after { content: " · admin only"; font-weight: 500; opacity: .6; }
body.tv-on #parent-tools .btn.danger,
body.tv-on .btn.danger, body.tv-on .danger-btn {
  background: rgba(179,49,42,0.10); color: #B3312A; border: 1px solid rgba(179,49,42,0.22);
  border-radius: 12px; font-weight: 620;
}
html[data-theme="dark"] body.tv-on .btn.danger,
html[data-theme="dark"] body.tv-on .danger-btn {
  background: rgba(255,138,128,0.13); color: #FF8A80; border-color: rgba(255,138,128,0.28);
}
body.tv-on #btn-unlock { width: 100%; }


/* ── Travellers ─────────────────────────────────────────────────────────
   Each traveller is an entity, so each is a tab. This replaces one text
   input holding "a, b, c" — a string could not carry a passport, a visa
   state or a link to a household member, which is why requirement 10 had
   nowhere to attach. */
body.tv-on .tv-pax { padding: 10px 12px; }
body.tv-on .tv-pax-ava {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: grid; place-items: center; color: #fff;
  font-size: 12px; font-weight: 700;
}
body.tv-on .tv-pax-x {
  background: none; border: 0; padding: 4px; cursor: pointer;
  color: var(--dv2-text-muted); display: grid; place-items: center;
}
body.tv-on .tv-pax-x:active { color: #B3312A; }
body.tv-on .tv-pax-empty {
  font-size: 13px; color: var(--dv2-text-sub);
  border: 1px dashed var(--tv-tile-bd); border-radius: var(--tv-rad);
  padding: 14px; margin: 0 0 10px; text-align: center;
}
body.tv-on .tv-pax-add { width: 100%; margin-top: 4px; gap: 7px;
  display: inline-flex; align-items: center; justify-content: center; }
body.tv-on .tv-pax-rows { margin-bottom: 10px; }


/* ── The destination board ──────────────────────────────────────────────*/
body.tv-on .tv-dest { padding: 12px 13px 4px; }
body.tv-on .tv-map-wrap {
  border-radius: var(--tv-rad); overflow: hidden;
  border: 1px solid var(--tv-tile-bd); box-shadow: var(--tv-shadow);
  margin-bottom: 11px; background: var(--tv-tile-bg);
}
body.tv-on .tv-map { height: 188px; }
body.tv-on .tv-legend {
  display: flex; gap: 13px; flex-wrap: wrap; padding: 8px 11px;
  border-top: 1px solid var(--tv-tile-bd);
  font-size: 11px; color: var(--dv2-text-sub);
}
body.tv-on .tv-legend span { display: inline-flex; align-items: center; gap: 6px; }
body.tv-on .tv-legend i {
  width: 15px; height: 0; border-top-width: 2.5px; border-top-style: solid;
  display: inline-block;
}
body.tv-on .tv-ic-wrap { color: var(--dv2-text-sub); display: flex; flex: none; }
body.tv-on .tv-chev { color: var(--dv2-text-muted); display: flex; }
body.tv-on #trip-dest .tv-tile { cursor: pointer; }
body.tv-on #trip-dest .tv-tile:active { transform: scale(.99); }

/* Map markers */
.tv-home-dot {
  width: 12px; height: 12px; border-radius: 50%;
  background: #16132B; border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,.35);
}
.tv-pin { filter: drop-shadow(0 2px 4px rgba(0,0,0,.3)); }
.tv-veh { filter: drop-shadow(0 1px 3px rgba(0,0,0,.35)); }
.tv-veh svg { display: block; }
.tv-veh-g { transform-origin: 0 0; transform-box: view-box; }

/* The trip header carries the destination now, so the packing segmented
   control is no longer the first thing under it. */
body.tv-on #view-trip .seg { margin-top: 10px; }


/* The packing controls, now below the destination board rather than pinned
   above it in the header. */
body.tv-on .tv-packhead { padding: 4px 13px 0; }
body.tv-on .tv-packhead .seg { margin: 0 0 10px; }
body.tv-on .tv-packhead .overall { margin: 0 0 6px; }

/* A map that could not load its tiles used to leave a white slab the height
   of the map. Drawn fallback instead: the same route, the same legend, no
   network. It is also what a phone in aeroplane mode sees — which is exactly
   when someone opens their trip. */
body.tv-on .tv-map-fallback {
  height: 188px; display: block; width: 100%;
  background: linear-gradient(170deg, #DDE7F2, #C9D9EA);
}
html[data-theme="dark"] body.tv-on .tv-map-fallback {
  background: linear-gradient(170deg, #182338, #101828);
}


/* The add-item FAB floats over the bottom of the scroller. The destination
   board ends where the packing list begins, so without this the last
   readiness tile sits under the button. */
body.tv-on .tv-dest { padding-bottom: 10px; }
body.tv-on #view-trip #list { padding-bottom: 96px; }


/* ── Hotel lookup (req 3) ───────────────────────────────────────────────*/
body.tv-on .tv-lookup { margin: 4px 0 10px; }
body.tv-on .tv-lookup-row { cursor: pointer; padding: 11px 12px; }
body.tv-on .tv-lookup-status {
  font-size: 12.5px; color: var(--dv2-text-sub);
  display: flex; align-items: center; gap: 8px; margin: 2px 2px 8px;
}
body.tv-on .tv-spin {
  width: 13px; height: 13px; border-radius: 50%; flex: none;
  border: 2px solid var(--tv-tile-bd); border-top-color: var(--dv2-link, #5b4fe0);
  animation: tv-spin .7s linear infinite;
}
@keyframes tv-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .tv-spin { animation: none; } }

body.tv-on .tv-hotel-card { margin: 2px 0 8px; }
body.tv-on .tv-hotel-row { padding: 10px 12px; display: block; text-decoration: none; }
body.tv-on a.tv-hotel-row { color: inherit; }
body.tv-on .tv-hotel-v { font-size: 13.5px; font-weight: 600; word-break: break-word; }
body.tv-on .tv-hotel-clear { width: 100%; margin-top: 4px; }


/* ── Itinerary (req 7) ──────────────────────────────────────────────────*/
body.tv-on .tv-itin-empty { text-align: center; padding: 18px 14px; }
body.tv-on .tv-itin-title { margin-bottom: 8px; }
body.tv-on .tv-itin-row {
  display: flex; align-items: flex-start; gap: 10px; padding: 7px 0;
}
body.tv-on .tv-itin-row + .tv-itin-row { border-top: 1px solid var(--dv2-divider, var(--tv-tile-bd)); }
body.tv-on .tv-itin-time {
  width: 42px; flex: none; font-size: 11.5px; font-weight: 700;
  color: var(--dv2-text-sub); padding-top: 2px;
  font-variant-numeric: tabular-nums;
}
body.tv-on .tv-itin-t { font-size: 14px; }
/* A day the generator deliberately left clear reads as a decision, not a gap. */
body.tv-on .tv-itin-quiet { border-style: dashed; background: transparent; box-shadow: none; }
body.tv-on #itin-actions { display: flex; gap: 8px; }
body.tv-on #itin-actions .btn { flex: 1; }


/* ── Passport / visa screens ────────────────────────────────────────────*/
body.tv-on .tv-pax-sum { text-align: center; padding: 18px 14px; margin-bottom: 12px; }
body.tv-on .tv-big {
  font-size: 32px; font-weight: 800; letter-spacing: -0.03em; line-height: 1.05;
  font-variant-numeric: tabular-nums; margin-bottom: 4px;
}
body.tv-on .tv-big.good { color: #16704A; }
body.tv-on .tv-big.warn { color: #A25C00; }
body.tv-on .tv-big.unknown { color: var(--dv2-text-sub); }
html[data-theme="dark"] body.tv-on .tv-big.good { color: #5DD48F; }
html[data-theme="dark"] body.tv-on .tv-big.warn { color: #E5A44A; }
body.tv-on .tv-goodbg { background: rgba(22,112,74,0.09);
  border-color: color-mix(in srgb, #16704A 30%, transparent); }
body.tv-on .tv-warnbg { background: rgba(162,92,0,0.10);
  border-color: color-mix(in srgb, #A25C00 30%, transparent); }
body.tv-on .tv-dashed { border-style: dashed; box-shadow: none; background: transparent; }
body.tv-on .tv-divider { height: 1px; background: var(--dv2-divider, var(--tv-tile-bd)); margin: 10px 0 8px; }
body.tv-on .tv-pax-addpp { width: 100%; margin-top: 10px; }
body.tv-on #visa-actions { display: flex; gap: 8px; }
body.tv-on #visa-actions .btn { flex: 1; text-align: center; text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center; }


/* ── prvConfirm ─────────────────────────────────────────────────────────
   Not gated on tv-on: the dialog is mounted on <body>, and it replaces the
   browser's own box everywhere it is used. Namespaced instead. */
.prv-confirm-ov .discard-card {
  background: var(--tv-sheet-bg, #fff);
  border: 1px solid rgba(20,16,38,0.08);
  border-radius: 18px;
}
html[data-theme="dark"] .prv-confirm-ov .discard-card {
  background: #1D2130; border-color: rgba(255,255,255,0.12); color: #EFEDF8;
}
.prv-confirm-ov .discard-go.is-danger { background: #B3312A; color: #fff; }
html[data-theme="dark"] .prv-confirm-ov .discard-go.is-danger { background: #C7443C; }
.prv-confirm-ov .discard-keep:focus-visible,
.prv-confirm-ov .discard-go:focus-visible { outline: 2px solid #6341E8; outline-offset: 2px; }


/* The converted glyphs sit where Material Symbols used to, so they need the
   same slots those occupied — .settings-ic and .t-seg-ic were sized for a
   font glyph, not an SVG. A glyph emitted without a size rendered a 290px
   row in Profile once; that is why every caller sizes its own. */
body.tv-on .settings-ic.tv-ic,
body.tv-on .settings-ic > .tv-ic { width: 22px; height: 22px; }
body.tv-on .t-seg-ic.tv-ic,
body.tv-on .t-seg-btn .tv-ic { width: 21px; height: 21px; display: block; margin: 0 auto 3px; }
body.tv-on .tp-af-spark.tv-ic { width: 20px; height: 20px; color: var(--dv2-link, #5b4fe0); }
body.tv-on .tp-af-upload .tv-ic,
body.tv-on .tp-af-scan-link .tv-ic { width: 18px; height: 18px; }
body.tv-on .settings-ic { display: inline-flex; align-items: center; justify-content: center; }


/* The hero glyph, replacing the 3D suitcase PNG. The hero is a saturated
   gradient, so the glyph is white on it rather than token-coloured. */
body.tv-on .t-hero-img { display: inline-flex; align-items: center; justify-content: center; }
body.tv-on .t-hero-img .tv-ic { width: 34px; height: 34px; color: #fff; opacity: .95; }
body.tv-on .t-hero-mode .tv-ic,
body.tv-on #t-hero-mode svg { color: #fff; }


/* ── The auto-injected close button ─────────────────────────────────────
   ensureSheetCloseButtons() appends a .sheet-close to EVERY sheet, absolutely
   positioned top-right. style.css keeps content clear of it with

       .sheet > h2:first-of-type { padding-right: 54px }

   — a DIRECT-CHILD selector. These sheets wrap their heading in .sheet-head,
   so the h2 is a grandchild, the rule never applied, and the X landed on top
   of the first card. Reserve the gutter properly instead of relying on a
   selector that only fits one markup shape. */
#sheet-passports, #sheet-itinerary {
  padding-top: 18px;
}
#sheet-passports > .sheet-head,
#sheet-itinerary > .sheet-head,
#sheet-passports > .hint,
#sheet-itinerary > .hint,
#sheet-passports > p,
#sheet-itinerary > p {
  padding-right: 56px;
}
/* The first card sits below the X, never beside it. */
#sheet-passports #pax-summary,
#sheet-itinerary #itin-body { margin-top: 6px; }


/* ── Past-trip separator ────────────────────────────────────────────────
   A labelled rule. A bare line says "something changes here"; it does not say
   what, and the thing being said is that everything below is a memory. */
body.tv-on .tv-past-sep {
  display: flex; align-items: center; gap: 12px;
  margin: 20px 2px 12px; color: var(--dv2-text-sub);
  font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
}
body.tv-on .tv-past-sep::before,
body.tv-on .tv-past-sep::after {
  content: ""; flex: 1; height: 1px; background: var(--tv-tile-bd);
}
body.tv-on .tv-next-chip {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.04em;
  padding: 3px 8px; border-radius: 100px; white-space: nowrap;
  color: var(--dv2-link, #5b4fe0); background: rgba(91,79,224,0.10);
  align-self: flex-start;
}
html[data-theme="dark"] body.tv-on .tv-next-chip {
  color: #9B85FF; background: rgba(155,133,255,0.15);
}


/* ── Mixed journeys: the leg builder ────────────────────────────────────*/
body.tv-on .tv-legs-wrap { margin-top: 14px; }
body.tv-on .tv-legs-lede { font-size: 12.5px; color: var(--dv2-text-sub); margin: 0 2px 10px; }
body.tv-on .tv-legs { margin-bottom: 10px; }
body.tv-on .tv-leg {
  display: flex; align-items: center; gap: 10px;
  background: var(--tv-tile-bg); border: 1px solid var(--tv-tile-bd);
  border-radius: 14px; padding: 9px 11px; box-shadow: var(--tv-shadow);
}
body.tv-on .tv-leg-n {
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-size: 11px; font-weight: 700;
  background: var(--dv2-link, #5b4fe0); color: #fff;
  font-variant-numeric: tabular-nums;
}
body.tv-on .tv-leg-ic { color: var(--dv2-link, #5b4fe0); display: flex; flex: none; }
body.tv-on .tv-leg-t { flex: 1; font-size: 14px; font-weight: 620; }
body.tv-on .tv-leg-up {
  background: none; border: 0; padding: 4px; cursor: pointer;
  color: var(--dv2-text-muted); display: grid; place-items: center;
}
body.tv-on .tv-leg-up:disabled { opacity: .25; }
/* The connector between legs — the journey reads as a chain, not a list. */
body.tv-on .tv-leg-join {
  width: 2px; height: 12px; margin: 0 0 0 21px;
  background: var(--tv-tile-bd); border-radius: 2px;
}
body.tv-on .tv-legs-add { display: flex; flex-wrap: wrap; gap: 7px; }
body.tv-on .tv-leg-add {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; padding: 7px 12px;
}
body.tv-on .tv-leg-add svg { color: var(--dv2-link, #5b4fe0); }

/* The interchange marker: where one vehicle hands over to the next. */
.tv-interchange {
  width: 11px; height: 11px; border-radius: 50%;
  background: #fff; border: 2.5px solid #6341E8;
  box-shadow: 0 1px 4px rgba(0,0,0,.3);
}
/* The swap, so a handover is noticed on a small screen. */
.tv-veh-swap { animation: tv-veh-pop .42s ease; }
@keyframes tv-veh-pop {
  0%   { transform: scale(.55); opacity: .3; }
  55%  { transform: scale(1.18); opacity: 1; }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) { .tv-veh-swap { animation: none; } }

/* ===== THE TRAVEL MEMORY BOOK (b169) ======================================
   The collection is the subject, so the screen reads top to bottom as: where
   we have been (map) → over which years (filter) → what that adds up to
   (stats) → what is next (one line) → the book. Everything here is gated on
   body.tv-on, so none of it can land on another screen. */

/* --- the year filter ---------------------------------------------------- */
body.tv-on .tv-years {
  display: flex;
  gap: 6px;
  margin: 14px 2px 12px;
  padding: 4px;
  border-radius: 100px;
  background: var(--tv-tile-bg);
  border: 1px solid var(--tv-tile-bd);
}
body.tv-on .tv-year {
  flex: 1;
  padding: 8px 10px;
  border: none;
  border-radius: 100px;
  background: none;
  color: var(--dv2-text-sub);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  transition: background .18s var(--ease-out), color .18s var(--ease-out);
}
body.tv-on .tv-year.on {
  background: var(--dv2-text-primary);
  color: var(--tv-ink-on-dark);
}

/* --- what it adds up to -------------------------------------------------
   Three numbers, equal weight, no chrome between them. This is the line the
   whole screen exists to be able to show. */
body.tv-on .tv-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin: 0 2px 16px;
}
body.tv-on .tv-stat {
  display: flex;
  min-width: 0;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 14px 6px;
  border-radius: var(--tv-rad, 18px);
  background: var(--tv-tile-bg);
  border: 1px solid var(--tv-tile-bd);
}
body.tv-on .tv-stat b { display: block;
  font-size: 26px;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--dv2-link, #5b4fe0);
}
body.tv-on .tv-stat small { display: block;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--dv2-text-sub);
}

/* --- what is coming up ------------------------------------------------
   b169 made this a single quiet line, to stop a future trip's packing progress
   from being the headline of a screen about memories. b170 keeps that rule and
   changes the shape: the approved design gives an upcoming journey the same
   photograph-led card as a memory, because it is an entry in the book that has
   not been written yet. It still never leads with readiness — the passports
   pill sits under the picture, where it is a footnote. */
body.tv-on .tv-next { margin: 0 2px 4px; }

/* --- the book: a heading per year --------------------------------------- */
body.tv-on .tv-year-sep {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 24px 2px 12px;
}
body.tv-on .tv-year-sep span {
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--dv2-text-primary);
}
body.tv-on .tv-year-sep i {
  font-style: normal;
  font-size: 11.5px;
  color: var(--dv2-text-sub);
}
body.tv-on .tv-year-sep::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--tv-tile-bd);
}

/* --- nothing to show yet ------------------------------------------------- */
body.tv-on .tv-empty {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 28px 20px;
  border-radius: var(--tv-rad, 18px);
  background: var(--tv-tile-bg);
  border: 1px dashed var(--tv-tile-bd);
  text-align: center;
}
body.tv-on .tv-empty b { font-size: 15px; color: var(--dv2-text-primary); }
body.tv-on .tv-empty span { font-size: 13px; color: var(--dv2-text-sub); line-height: 1.45; }


/* ══════════════════════════════════════════════════════════════════════════
   THE MEMORY BOOK — b170
   The approved design, built. Everything below is gated on body.tv-on so it
   cannot land on another screen, and every colour comes from a token that
   already existed: this adds components, not a palette.
   ══════════════════════════════════════════════════════════════════════════ */

/* --- a section of the book ---------------------------------------------
   "Going next" and "Where we have been" are the two halves of the question
   the section exists to answer, so they are said out loud rather than left
   for the reader to infer from ordering. */
body.tv-on .tv-booksec {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 22px 2px 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--dv2-text-sub);
}
body.tv-on .tv-booksec::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--tv-tile-bd);
}
/* "Where we have been" is immediately followed by the first year heading, and
   both carry their own top margin — which stacked into a hole the size of a
   card. The section heading has already done the spacing. */
body.tv-on #trip-list > .tv-year-sep:first-child { margin-top: 4px; }

/* --- THE MEMORY CARD ----------------------------------------------------
   A photograph across the full width, and the caption beneath it. The card it
   replaced put a 92px thumbnail on the right and the text on the left, which
   is the shape of a database row; this is the shape of a page in an album. */
body.tv-on .tv-entry {
  display: block;
  width: 100%;
  padding: 0;
  margin: 0 0 12px;
  border: 1px solid var(--tv-tile-bd);
  border-radius: var(--tv-rad, 16px);
  background: var(--tv-tile-bg);
  box-shadow: var(--tv-shadow);
  overflow: hidden;
  text-align: left;
  color: var(--dv2-text-primary);
  font-family: inherit;
  cursor: pointer;
  animation: tv-entry-in .34s var(--ease-out, cubic-bezier(.32,.72,0,1)) both;
}
body.tv-on .tv-entry:active { transform: scale(.988); }
@keyframes tv-entry-in {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  body.tv-on .tv-entry { animation: none; }
  body.tv-on .tv-entry:active { transform: none; }
}

/* The photograph. Proportions carried over from the approved design: the
   upcoming card is a little taller than a memory, because it is the one you
   are about to live. */
body.tv-on .tv-entry-ph {
  display: block;
  position: relative;
  width: 100%;
  height: 118px;
  background-size: cover;
  background-position: center;
  background-color: var(--tv-tile-bd);
}
body.tv-on .tv-entry.is-next .tv-entry-ph { height: 128px; }

body.tv-on .tv-entry-cap {
  display: block;
  padding: 11px 13px 12px;
}
body.tv-on .tv-entry-row { display: flex; align-items: center; gap: 10px; }
body.tv-on .tv-entry-id { flex: 1; min-width: 0; display: block; }
body.tv-on .tv-entry-id b {
  display: block;
  font-size: 16px;
  font-weight: 680;
  letter-spacing: -0.015em;
  color: var(--dv2-text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.tv-on .tv-entry-id small {
  display: block;
  font-size: 12.5px;
  color: var(--dv2-text-sub);
  margin-top: 1px;
}
body.tv-on .tv-entry-mode {
  flex: none;
  width: 20px;
  height: 20px;
  color: var(--dv2-link, #5b4fe0);
}
body.tv-on .tv-entry-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 9px;
}
body.tv-on .tv-entry-gap { flex: 1; }

/* Traveller faces. Their own rule now — the old ones were written against
   `.trip-card.tc2`, which no longer exists. */
body.tv-on .tc-avatars { display: flex; }
body.tv-on .tc-ava {
  width: 25px;
  height: 25px;
  border-radius: 50%;
  border: 2px solid var(--dv2-surface, #fff);
  margin-left: -7px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10.5px;
  font-weight: 700;
  color: #fff;
  flex: none;
}
body.tv-on .tc-ava:first-child { margin-left: 0; }
body.tv-on .tc-ava-more { background: var(--tv-tile-bd) !important; color: var(--dv2-text-sub); }
html[data-theme="dark"] body.tv-on .tc-ava { border-color: #1b1b22; }

/* --- whose picture is this? --------------------------------------------
   A well-known view of the city is a good stand-in and a bad lie. */
body.tv-on .tv-autochip {
  position: absolute;
  right: 8px;
  top: 8px;
  z-index: 2;
  font-size: 10px;
  font-weight: 650;
  letter-spacing: 0.02em;
  padding: 3px 9px;
  border-radius: 100px;
  background: rgba(0,0,0,0.44);
  color: #fff;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  pointer-events: none;
}

/* --- the map and what it adds up to, as ONE object ----------------------
   Three stat cards floating loose beneath a map are three things; the map and
   its own total are one thing, and the card says so. */
body.tv-on .tv-mapcard {
  display: block;
  width: 100%;
  padding: 0;
  margin: 0 0 4px;
  border: 1px solid var(--tv-tile-bd);
  border-radius: var(--tv-rad, 16px);
  background: var(--tv-tile-bg);
  box-shadow: var(--tv-shadow);
  overflow: hidden;
  cursor: pointer;
  font-family: inherit;
  color: inherit;
}
body.tv-on .tv-mapcard:active { transform: scale(.992); }
@media (prefers-reduced-motion: reduce) {
  body.tv-on .tv-mapcard:active { transform: none; }
}
/* THE MAP STAYS A MAP.
   Making the whole card one button meant killing pointer events on the map
   inside it — which took pinch-zoom and pan with it, so after the plane landed
   you could no longer zoom out to see everywhere you had been. The map keeps
   its gestures; the strip underneath is the way through to the full screen. */
body.tv-on .tv-mapcard {
  cursor: default;
}
body.tv-on .tv-mapcard #trip-map {
  height: 190px;
  border-radius: 0;
  margin: 0;
}
body.tv-on .tv-mapcard:active { transform: none; }
body.tv-on .tv-mapfoot {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 0;
  border: none;
  border-top: 1px solid var(--tv-tile-bd);
  background: none;
  color: inherit;
  font-family: inherit;
  cursor: pointer;
}
body.tv-on .tv-mapfoot:active { background: var(--tv-tile-bd); }
body.tv-on .tv-mapfoot .tv-stats { flex: 1; }
body.tv-on .tv-mapfoot-go {
  flex: none;
  display: flex;
  align-items: center;
  gap: 3px;
  padding-right: 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--dv2-link, #5b4fe0);
  white-space: nowrap;
}
body.tv-on .tv-mapcard .tv-stats {
  grid-template-columns: repeat(3, 1fr);
  margin: 0;
  padding: 9px;
  gap: 7px;
}
body.tv-on .tv-mapcard .tv-stat {
  background: transparent;
  border: none;
  padding: 4px 2px;
}
body.tv-on .tv-mapcard .tv-stat b { font-size: 22px; }

/* --- the drawn map, for when there is no signal ------------------------- */
/* The drawn map keeps its own proportions. Slicing a 260x200 map into a fixed
   190px band cut Scandinavia off the top and the bottom of Iberia off the
   foot of it — a map of where you have been that cannot show where you went. */
body.tv-on .tv-map-drawn { background: #9BC2DE; height: auto !important; }
body.tv-on .tv-vec { display: block; width: 100%; height: auto; }
body.tv-on .tv-vec-pin { cursor: pointer; pointer-events: auto; }

/* --- OUR MAP, the screen ------------------------------------------------ */
body.tv-on .tvm-map {
  width: 100%;
  height: 300px;
  border-radius: var(--tv-rad, 16px);
  overflow: hidden;
  margin: 12px 0 12px;
  background: #9BC2DE;
  position: relative;
}
body.tv-on .tvm-note { text-align: left; padding: 13px 15px; margin-bottom: 4px; }
body.tv-on .tvm-note b { font-size: 13.5px; }
body.tv-on .tvm-countries { display: block; }
body.tv-on .tvm-country { cursor: pointer; }
body.tv-on .tvm-country .tv-row { width: 100%; }
body.tv-on .tvm-country .tv-t,
body.tv-on .tvm-country .tv-s { display: block; }
body.tv-on .tvm-country .tv-s {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The report, at the foot of the map screen. One of its own rounded tabs,
   like every other entity in Travel — not a link floating on the background. */
body.tv-on .tvm-report {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin: 14px 0 6px;
  padding: 14px 15px;
  text-align: left;
  border: 1px solid var(--tv-tile-bd);
  border-radius: var(--tv-rad, 16px);
  background: var(--tv-tile-bg);
  box-shadow: var(--tv-shadow, none);
  color: var(--dv2-text-primary);
  cursor: pointer;
}
body.tv-on .tvm-report:focus-visible { outline: 2px solid var(--dv2-link); outline-offset: 2px; }
body.tv-on .tvm-report .tv-ic { width: 22px; height: 22px; flex: none; }
body.tv-on .tvm-report-txt { flex: 1 1 auto; min-width: 0; }
body.tv-on .tvm-report-txt b {
  display: block;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--dv2-text-primary);
}
body.tv-on .tvm-report-txt small {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--dv2-text-sub);
}
body.tv-on .tvm-report .settings-chev { color: var(--dv2-text-muted); flex: none; }

body.tv-on .tvm-pin {
  border: 2px solid #fff;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  box-shadow: 0 1px 4px rgba(0,0,0,.4);
}

/* --- THE TRIP, AS A PAGE ------------------------------------------------
   The photograph first, at the size a photograph deserves. */
body.tv-on .tv-hero {
  position: relative;
  display: block;
  height: 232px;
  margin: 0 0 14px;
  border-radius: var(--tv-rad, 16px);
  overflow: hidden;
  background-size: cover;
  background-position: center;
  background-color: var(--tv-tile-bd);
}
body.tv-on .tv-hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,.30) 0%, rgba(0,0,0,0) 42%, rgba(0,0,0,.74) 100%);
}
body.tv-on .tv-hero-txt {
  position: absolute;
  left: 15px;
  right: 15px;
  bottom: 13px;
  display: block;
  color: #fff;
}
body.tv-on .tv-hero-eyebrow {
  display: block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  opacity: .88;
}
body.tv-on .tv-hero-name {
  display: block;
  font-size: 30px;
  font-weight: 720;
  letter-spacing: -0.03em;
  line-height: 1.06;
  margin-top: 3px;
}
body.tv-on .tv-hero-sub {
  display: block;
  font-size: 13px;
  opacity: .86;
  margin-top: 1px;
}

/* The hero says the name, over the photograph, at the size the approved design
   sets it. The sticky bar above it was saying the same name and the same dates
   again two lines higher — and the countdown a third time. One of them has to
   go, and it is not the photograph. The bar keeps its controls. */
body.tv-on #view-trip .topbar .title-wrap { display: none; }
body.tv-on #view-trip #countdown { display: none; }

body.tv-on .tv-kept-who { margin-bottom: 4px; }

/* --- the booking-first screen ------------------------------------------- */
body.tv-on #trip-form .tp-or { margin-top: 20px; }
body.tv-on #trip-form .tp-photo-later {
  margin-top: 14px;
  text-align: center;
  font-size: 12.5px;
  color: var(--dv2-text-sub, #8b8a98);
}

/* --- the fold control, beside what it folds ----------------------------- */
body.tv-on .tv-packsec {
  display: flex;
  align-items: center;
  gap: 10px;
}
body.tv-on .tv-foldbtn {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 11px;
  border-radius: 100px;
  border: 1px solid var(--tv-tile-bd);
  background: var(--tv-tile-bg);
  color: var(--dv2-text-sub);
  font: inherit;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0;
  text-transform: none;
  cursor: pointer;
}
body.tv-on .tv-foldbtn:active { transform: scale(.97); }
body.tv-on .tv-foldbtn-ic { transition: transform .2s var(--ease-out); }
body.tv-on .tv-foldbtn.folded .tv-foldbtn-ic { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  body.tv-on .tv-foldbtn:active { transform: none; }
  body.tv-on .tv-foldbtn-ic { transition: none; }
}

/* --- positioning a picture ---------------------------------------------
   Two previews, because the picture is shown in two shapes and choosing a
   framing without seeing both is guessing. */
body.tv-on .focus-body { padding: 4px 16px 20px; display: flex; flex-direction: column; gap: 8px; }
body.tv-on .focus-lab {
  margin: 6px 0 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--i26-tx2, #8a8a8e);
}
body.tv-on .focus-frame {
  width: 100%;
  border-radius: 16px;
  background-color: rgba(120,120,140,.16);
  background-repeat: no-repeat;
  background-size: cover;
  cursor: grab;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}
body.tv-on .focus-frame:active { cursor: grabbing; }
/* The two shapes, at the proportions they really are on the phone. */
body.tv-on .focus-hero { aspect-ratio: 358 / 232; }
body.tv-on .focus-band { aspect-ratio: 358 / 118; }
body.tv-on .focus-centre { align-self: center; margin-top: 6px; }

/* --- the map pin -------------------------------------------------------- */
body.tv-on .tv-mappin {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  line-height: 0;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,.3));
}
body.tv-on .tv-mappin.is-past { opacity: .9; }
body.tv-on .tv-mappin:active { transform: scale(.94); }
@media (prefers-reduced-motion: reduce) {
  body.tv-on .tv-mappin:active { transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   b172 — the memory book keeps only what the household put in it
   ══════════════════════════════════════════════════════════════════════════ */

/* --- the close button, pinned rather than floating -----------------------
   Not gated on tv-on: `.sheet` is app-wide and the defect was app-wide. The
   rail is zero-height and sticky, so the X stays at the top of what you can
   SEE instead of the top of what you could scroll to. */
.sheet-closerail {
  position: sticky;
  top: 0;
  z-index: 40;
  height: 0;
  display: flex;
  justify-content: flex-end;
  pointer-events: none;       /* the rail spans the sheet; only the X is live */
}
/* A pinned control has to have ground under it. Without this the X is an
   opaque chip sitting on whatever row happened to scroll beneath it, which
   reads as a collision; with it, content fades out behind a header band and
   the button reads as chrome. Purely decorative — it never eats a tap. */
.sheet-closerail::before {
  content: "";
  position: absolute;
  left: calc(var(--pad, 16px) * -1);
  right: calc(var(--pad, 16px) * -1);
  top: calc((var(--sp-5, 20px)) * -1);
  height: 74px;
  background: linear-gradient(180deg,
      var(--card-surface) 0%, var(--card-surface) 54%, transparent 100%);
  pointer-events: none;
  z-index: -1;
}
.sheet-closerail > .sheet-close {
  position: static;           /* the rail does the positioning now */
  pointer-events: auto;
  flex: none;
  transform: translateY(2px);
}
/* Nothing may run underneath it. The old rule only reached a direct-child
   `h2:first-of-type`, so every sheet whose title sits inside `.sheet-head` —
   which is most of Travel's — had its heading overlapped. */
.sheet .sheet-head { padding-right: 52px; }
.sheet .sheet-head h2 { min-width: 0; }
.sheet > .sheet-lede { padding-right: 52px; }
.sheet > .grabber { margin-top: 0; }

/* --- a row that is missing something offers to fix it -------------------- */
body.tv-on .tv-fill {
  display: block;
  width: 100%;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  color: var(--dv2-text-primary);
}
body.tv-on .tv-fill .tv-row { width: 100%; }
body.tv-on .tv-fill:active { transform: scale(.99); }
body.tv-on .tv-fill.is-empty { border-style: dashed; }
body.tv-on .tv-s.is-empty { color: var(--dv2-text-muted); font-style: italic; }
body.tv-on .tv-add {
  flex: none;
  display: inline-flex;
  align-items: center;
  padding: 6px 13px;
  border-radius: 100px;
  background: var(--dv2-link, #5b4fe0);
  color: #fff;
  font-size: 12px;
  font-weight: 650;
  white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
  body.tv-on .tv-fill:active { transform: none; }
}

/* --- packing templates --------------------------------------------------- */
body.tv-on .packtpl-body { display: flex; flex-direction: column; gap: 9px; }
body.tv-on .packtpl {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 14px 15px;
  border-radius: var(--tv-rad, 16px);
  border: 1px solid var(--tv-tile-bd);
  background: var(--tv-tile-bg);
  box-shadow: var(--tv-shadow);
  text-align: left;
  font-family: inherit;
  color: var(--dv2-text-primary);
  cursor: pointer;
}
body.tv-on .packtpl:active { transform: scale(.99); }
body.tv-on .packtpl-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
body.tv-on .packtpl-txt b { font-size: 15px; font-weight: 650; }
body.tv-on .packtpl-txt small { font-size: 12.5px; color: var(--dv2-text-sub); }
body.tv-on .packtpl-ic {
  flex: none; width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--dv2-g-07-bg, rgba(91,79,224,.09));
  color: var(--dv2-link, #5b4fe0);
}
body.tv-on .packtpl-own {
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--dv2-link, #5b4fe0);
}
body.tv-on .trip-docs-actions { display: flex; flex-direction: column; gap: 9px; margin-bottom: 4px; }
@media (prefers-reduced-motion: reduce) {
  body.tv-on .packtpl:active { transform: none; }
}
