/* The client area, logged out.
 *
 * Like 90-beta.css this has no production counterpart, and like it, every colour and face comes
 * from the site's own Elementor kit (kit 74: --e-global-color-primary is the brand purple
 * #9108DC, --e-global-color-c24263e the page grey, DM Sans for text, Poppins for headings), so
 * the page reads as part of qlesspark.com rather than as an app bolted onto it.
 *
 * Three ideas carry the whole design:
 *   .ca-slot    a per-client value that is not filled in yet. Named, not invented — the chip
 *               says "fecha de inicio", never a plausible-looking date, because a made-up date
 *               on a sales page is a promise.
 *   .ca-locked  an action a paying customer would take. It looks like a control, because it is
 *               one; it opens the modal instead of doing the thing.
 *   .ca-cta     the purchase, in exactly one visual style, wherever it appears.
 */

/* Why every button selector is doubled (.ca-cta.ca-cta and friends): the Elementor kit paints
 * every <button> on the site purple with white text —
 *   .elementor-kit-74 button { background-color: var(--e-global-color-primary); color: #fff }
 * — and that is (0,1,1), so a plain .ca-cta at (0,1,0) loses to it however late it is loaded.
 * Repeating the class is the smallest fix that keeps the selector self-contained; scoping under
 * an ancestor would not work for the modal and the pinned bar, which sit outside .ca. */

.ca {
  width: 100%;
  max-width: 62rem;
  margin: 0 auto;
  padding: 32px 0 40px;
  font-family: "DM Sans", Sans-serif;
  font-size: 17px;
  line-height: 27px;
  color: var(--ca-ink);
  text-align: left;
}

/* On <body> and not on .ca. The modal and the pinned bar are siblings of the page content, not
   children of it, so a token declared on .ca would be undefined in exactly the two places the
   purchase button appears — and `background: var(--ca-accent)` with no value resolves to
   transparent, i.e. a white button on a white modal. <body> and not :root because the kit's own
   variables live on body.elementor-kit-74, so --ca-accent can follow the brand colour rather
   than repeat its hex. This stylesheet only loads on this page. */
body {
  --ca-ink: #16202e;
  --ca-muted: #5a6b80;
  --ca-line: #dfe5ec;
  --ca-card: #ffffff;
  --ca-accent: var(--e-global-color-primary, #9108dc);
  --ca-bad: #b42318;
}

/* The Elementor container this page's markup sits in is a flex row, and a flex item's default
   min-width is auto — it refuses to shrink below the widest thing inside it. At 390px that made
   the whole column 443px wide and clipped it against the container's overflow:hidden, so every
   line of copy lost its right-hand end. Nothing to do with the copy; it is the one place a
   hand-written block inside an Elementor document has to say so explicitly. */
.ca-host, .ca-host > .elementor-widget-container { min-width: 0; max-width: 100%; }
.ca-section, .ca-preview, .ca-form { min-width: 0; }

/* Something in the site's own CSS puts `white-space: nowrap` on buttons, and these have real
   sentences on them — "Reserva fuera del parque (hotel o Disney Village)" is 386px of one line
   inside a 292px button at 390px, which overflowed the page. Labels wrap; only .ca-badge, which
   is two or three words by design, keeps nowrap. */
.ca-locked.ca-locked, .ca-cta.ca-cta, .ca-ghost.ca-ghost,
.ca-tab.ca-tab, .ca-segbtn.ca-segbtn,
/* Added 25 August with the entry-block merge: "Ya he comprado mi viaje" became a <button>, and
   it is the first .ca-linkish that is not also .ca-locked - so it was the first one this rule
   did not already cover. */
.ca-linkish.ca-linkish { white-space: normal; }

.ca * { box-sizing: border-box; }
/* The three dialogs — the lock modal, the purchase and S0 — are siblings of .ca, not children
   of it, so they miss the rule above.
   That matters now that the purchase form lives in one: .ca-form input is width:100% plus
   0.7rem of padding and a border, and in content-box that is 24px wider than its column -
   which at 390px pushed the whole dialog off the right edge of the screen. */
.ca-modal, .ca-modal * { box-sizing: border-box; }

.ca-h2, .ca-h3 {
  margin: 0;
  font-family: "Poppins", Sans-serif;
  color: var(--e-global-color-8cd1398, #000);
  letter-spacing: 0;
}
.ca-h2 { font-size: 30px; line-height: 38px; font-weight: 600; }
.ca-h3 { font-size: 23px; line-height: 30px; font-weight: 600; }

.ca-prose p { margin: 0 0 0.9rem; }
.ca-prose p:last-child { margin-bottom: 0; }
.ca-prose ul, .ca-prose ol { margin: 0 0 0.9rem; padding-left: 1.2rem; }
.ca-prose li { margin: 0 0 0.35rem; }
.ca-prose strong { color: var(--ca-ink); }
.ca-listlead { font-weight: 600; }

/* ------------------------------------------------------------------ the empty values */
.ca-slot {
  display: inline-block;
  padding: 0 0.45rem;
  border: 1px dashed var(--ca-accent);
  border-radius: 6px;
  background: rgba(145, 8, 220, 0.06);
  font-size: 0.86em;
  font-weight: 600;
  font-style: normal;
  color: var(--ca-accent);
  white-space: nowrap;
}

.ca-legend {
  margin: 0 0 1.5rem;
  font-size: 15px;
  line-height: 24px;
  color: var(--ca-muted);
}
.ca-legend p { margin: 0; }

/* ------------------------------------------------------------------- preview banner */
.ca-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  align-items: center;
  justify-content: space-between;
  margin: 0 0 2rem;
  padding: 1.1rem 1.4rem;
  border: 1px solid var(--ca-accent);
  border-left: 5px solid var(--ca-accent);
  border-radius: 14px;
  background: var(--ca-card);
}
.ca-preview-text { flex: 1 1 22rem; }
.ca-preview-text p { margin: 0; }
.ca-preview-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: center;
}

/* PREVIEW SCAFFOLDING - delete this rule with the rest of the section numbers. See the header
   of shared/sections.mjs for the full list; this is item 6 of 6.

   Costs nothing when the flag is off, because with the flag off no element ever carries the
   class. user-select: all is the detail that makes it useful rather than decorative: a
   tap-and-hold on a phone selects the whole number and nothing else, which is how a number gets
   from the screen into a message. */
.ca-secno {
  display: inline-block;
  margin-right: 0.45em;
  padding: 0.05em 0.4em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.72em;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.02em;
  vertical-align: 0.12em;
  color: #fff;
  background: #b3261e;
  border-radius: 4px;
  user-select: all;
  -webkit-user-select: all;
}

/* ------------------------------------------------------- S0, the door back in (P-S0) */
/* A DIALOG SINCE 25 AUGUST 2026, opened from the one entry block. It used to be a bordered card
   sitting under the banner on all 28 pages of the area; .ca-volver and .ca-volver-h went with
   that card, because .ca-modal already draws the box and .ca-modal .ca-h3 already sets the
   heading. What is kept is everything about the CONTROL, which did not move and which #102 takes
   over unchanged: the same markup accepts an enabled input the day the magic link is wired.

   The field is disabled until then, and it is styled to LOOK unavailable rather than to look
   broken - dashed, which is the signal the .ca-slot chips and every locked control in this area
   already use. */
.ca-modal-volver { width: min(34rem, calc(100vw - 2rem)); }
.ca-modal-volver .ca-h3 { margin-top: 0; padding-right: 2rem; }
.ca-volver-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1rem;
  align-items: flex-end;
  margin-top: 0.9rem;
}
.ca-volver-field {
  flex: 1 1 20rem;
  min-width: 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 20px;
}
.ca-volver-field input {
  display: block;
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.65rem 0.7rem;
  font: inherit;
  font-size: 16px;
  font-weight: 400;
  color: var(--ca-ink);
  background: var(--ca-card);
  border: 1px solid var(--ca-line);
  border-radius: 8px;
}
/* Disabled, and it has to read as "not yet" rather than as "broken". Dashed is the same signal
   the .ca-slot chips and the locked controls use everywhere else in this area. */
.ca-volver-field input:disabled {
  border-style: dashed;
  color: var(--ca-muted);
  background: #fbfcfd;
  cursor: not-allowed;
}
.ca-modal-volver .ca-cta:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}
/* [hidden] beats the display the modal's own layout would give these. They are the three states
   #102 unhides; none of them can be reached today, because nothing submits. */
.ca-modal-volver .ca-note[hidden] { display: none; }

/* --------------------------------------------------------------------------- hero */
.ca-hero { margin: 0 0 0.5rem; }
.ca-hero .ca-h2 { margin-bottom: 0.8rem; }

.ca-steps {
  counter-reset: ca-step;
  list-style: none;
  margin: 1.4rem 0 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(3, 1fr);
}
.ca-steps li {
  counter-increment: ca-step;
  padding: 1rem 1.1rem 1.1rem;
  border: 1px solid var(--ca-line);
  border-radius: 12px;
  background: var(--ca-card);
  font-size: 16px;
  line-height: 25px;
}
.ca-step-title {
  display: block;
  margin-bottom: 0.2rem;
  font-family: "Poppins", Sans-serif;
  font-size: 17px;
  font-weight: 600;
  color: var(--e-global-color-8cd1398, #000);
}
.ca-steps li p { margin: 0 0 0.5rem; }
.ca-steps li p:last-child { margin-bottom: 0; }
.ca-step-cta { margin-top: 0.7rem; }
.ca-cta-sm.ca-cta-sm { padding: 0.5rem 1.1rem; font-size: 15px; line-height: 23px; }

.ca-steps li::before {
  content: counter(ca-step);
  display: grid;
  place-items: center;
  width: 1.7rem;
  height: 1.7rem;
  margin-bottom: 0.5rem;
  border-radius: 50%;
  background: var(--ca-accent);
  color: #fff;
  font-family: "Poppins", Sans-serif;
  font-size: 0.85rem;
  font-weight: 700;
}

/* ------------------------------------------------------------------- the short form */
/* It is inside <dialog id="ca-compra"> now, so it has no card of its own: the dialog is the
   card. What is left here is the field styling, which is the same in either place. */

.ca-form label {
  display: block;
  margin: 0 0 1rem;
  font-weight: 600;
  font-size: 15px;
  line-height: 22px;
}
.ca-form small {
  display: block;
  margin-top: 0.3rem;
  font-weight: 400;
  font-size: 13.5px;
  line-height: 20px;
  color: var(--ca-muted);
}
.ca-req { color: var(--ca-bad); font-weight: 400; }

.ca-form input, .ca-form select {
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.65rem 0.7rem;
  font: inherit;
  font-size: 16px;
  font-weight: 400;
  color: var(--ca-ink);
  background: var(--ca-card);
  border: 1px solid var(--ca-line);
  border-radius: 8px;
}
.ca-form input:focus, .ca-form select:focus {
  outline: 2px solid var(--ca-accent);
  outline-offset: 1px;
  border-color: var(--ca-accent);
}
.ca-form [aria-invalid="true"] { border-color: var(--ca-bad); }

.ca-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.2rem; }

.ca-kidages {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0 1.2rem;
}
.ca-kidages:empty { display: none; }

.ca-check {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 0.2rem 0 1.2rem;
  font-weight: 500;
}
.ca-check input { width: auto; margin: 0.3rem 0 0; flex: none; }

.ca-buyrow {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem 1.5rem;
  align-items: center;
  justify-content: space-between;
  padding-top: 0.4rem;
  border-top: 1px solid var(--ca-line);
}
.ca-price { margin: 0.8rem 0 0; }
.ca-price strong { font-family: "Poppins", Sans-serif; font-size: 24px; }
.ca-price span { display: block; font-size: 14px; color: var(--ca-muted); }

.ca-note { margin-top: 0.9rem; font-size: 14px; color: var(--ca-muted); }
.ca-note p { margin: 0; }

/* -------------------------------------------------------------- consent (#90)
   Two unticked boxes above the pay button. Deliberately NOT styled down: they are
   not fine print, they are the two things the sale is legally standing on, so they
   get body-sized text and a real hit area rather than 11px grey.
   .ca-form label is a stacked block (label above control) for the four questions;
   a checkbox has to be the other way round, hence the override. */
.ca-consents { margin-top: 1.1rem; display: grid; gap: 0.6rem; }
.ca-form label.ca-consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0 0.65rem;
  align-items: start;
  margin: 0;
  font-size: 15px;
  font-weight: 400;
  line-height: 1.45;
  cursor: pointer;
}
.ca-form .ca-consent input[type="checkbox"] {
  width: 20px;
  height: 20px;
  min-width: 20px;
  margin: 0.15rem 0 0;
  accent-color: var(--ca-accent, currentColor);
  cursor: pointer;
}
.ca-form .ca-consent [aria-invalid="true"],
.ca-form .ca-consent input[aria-invalid="true"] { outline: 2px solid var(--ca-bad); outline-offset: 2px; }
.ca-consent a { text-decoration: underline; }

.ca-errors {
  margin-top: 1rem;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--ca-bad);
  border-left: 4px solid var(--ca-bad);
  border-radius: 12px;
  font-size: 15px;
}
.ca-errors h3 { margin: 0 0 0.4rem; font-size: 15px; color: var(--ca-bad); }
.ca-errors ul { margin: 0; padding-left: 1.1rem; }

/* -------------------------------------------------------------------- the sections */
.ca-section {
  margin: 0 0 1.2rem;
  padding: 1.5rem 1.6rem;
  border: 1px solid var(--ca-line);
  border-radius: 16px;
  background: var(--ca-card);
}

.ca-section-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  margin: 0 0 0.9rem;
}

.ca-badge {
  display: inline-block;
  margin: 0;
  padding: 0.2rem 0.7rem 0.25rem;
  border-radius: 999px;
  background: rgba(145, 8, 220, 0.08);
  color: var(--ca-accent);
  font-family: "DM Sans", Sans-serif;
  font-size: 13px;
  font-weight: 600;
  line-height: 20px;
  white-space: nowrap;
}

.ca-list { margin-top: 1rem; color: var(--ca-muted); font-size: 16px; line-height: 25px; }

.ca-tip + .ca-tip { margin-top: 1.2rem; }
.ca-tip h4 {
  margin: 0 0 0.3rem;
  font-family: "Poppins", Sans-serif;
  font-size: 17px;
  font-weight: 600;
  color: var(--e-global-color-8cd1398, #000);
}
.ca-tip p { margin: 0; }

/* ---------------------------------------------------------------- the two states */
/* One rule pair, and everything else is a class in the markup. .ca-when-draft is on what only
   makes sense while the answers can still change; .ca-when-locked on what only makes sense once
   the Route has been built. Nothing is duplicated in the script. */
body[data-ca-state="draft"] .ca-when-locked { display: none; }
body[data-ca-state="locked"] .ca-when-draft { display: none; }

.ca-badge-locked { background: rgba(21, 47, 78, 0.08); color: var(--e-global-color-65e99da, #152f4e); }

/* A section whose answers are fixed should look fixed. Greying the copy would make it harder to
   read for no gain, so the signal is on the edge and on the controls. */
body[data-ca-state="locked"] .ca-lockable { border-color: #c9d2dd; background: #fbfcfd; }
body[data-ca-state="locked"] .ca-lockable .ca-locked.ca-locked {
  border-style: dashed;
  color: var(--ca-muted);
  background: transparent;
}
body[data-ca-state="locked"] .ca-lockable .ca-locked.ca-locked:hover,
body[data-ca-state="locked"] .ca-lockable .ca-locked.ca-locked:focus-visible {
  border-color: var(--e-global-color-65e99da, #152f4e);
  color: var(--e-global-color-65e99da, #152f4e);
}

.ca-statepicker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.9rem;
  align-items: center;
  margin: -1.2rem 0 2rem;
  padding: 0.6rem 0.9rem;
  border: 1px dashed var(--ca-line);
  border-radius: 12px;
  font-size: 14px;
  line-height: 22px;
  color: var(--ca-muted);
}
.ca-statepicker-label { font-weight: 600; }
.ca-statepicker-note { flex: 1 1 100%; }
.ca-statepicker-note p { margin: 0; }

.ca-seg { display: inline-flex; border: 1px solid var(--ca-line); border-radius: 999px; }
.ca-segbtn.ca-segbtn {
  padding: 0.3rem 0.9rem;
  border: 0;
  border-radius: 999px;
  background: transparent;
  font: inherit;
  font-weight: 600;
  color: var(--ca-muted);
  cursor: pointer;
}
.ca-segbtn.ca-segbtn[aria-pressed="true"] { background: var(--ca-accent); color: #fff; }

/* --------------------------------------------------------------------------- tabs */
.ca-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin: 0.2rem 0 1.2rem;
  border-bottom: 1px solid var(--ca-line);
}
.ca-tab.ca-tab {
  padding: 0.55rem 1rem 0.7rem;
  border: 0;
  border-bottom: 3px solid transparent;
  border-radius: 8px 8px 0 0;
  background: transparent;
  font-family: "DM Sans", Sans-serif;
  font-size: 16px;
  font-weight: 600;
  color: var(--ca-muted);
  cursor: pointer;
}
.ca-tab.ca-tab[aria-selected="true"] {
  border-bottom-color: var(--ca-accent);
  color: var(--ca-accent);
}
.ca-tabpanel[hidden] { display: none; }

/* ------------------------------------------------------- the two ways to generate */
/* Side by side and the same size, because the choice is genuine in both directions: sooner but
   blind to reservations not made yet, or later but built around them. */
.ca-choice {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin: 1.2rem 0 0;
}
.ca-option {
  display: flex;
  flex-direction: column;
  padding: 1.1rem 1.2rem 1.2rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  background: #fbfcfd;
}
.ca-option-title {
  margin: 0 0 0.5rem;
  font-family: "Poppins", Sans-serif;
  font-size: 18px;
  font-weight: 600;
  color: var(--e-global-color-8cd1398, #000);
}
.ca-option .ca-prose { flex: 1 1 auto; font-size: 15.5px; line-height: 24px; }
.ca-option .ca-actions { margin-top: 1rem; }
.ca-locked-primary.ca-locked-primary { border-color: var(--ca-accent); color: var(--ca-accent); }

.ca-aviso {
  margin-top: 1.1rem;
  padding: 0.8rem 1rem;
  border-radius: 12px;
  background: rgba(145, 8, 220, 0.05);
  font-size: 15px;
  line-height: 24px;
  color: var(--ca-ink);
}
.ca-aviso p { margin: 0; }

/* --------------------------------------------------------------- the locked actions */
.ca-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.2rem;
}

.ca-locked.ca-locked {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.1rem 0.6rem 0.9rem;
  border: 1px solid var(--ca-line);
  border-radius: 100px;
  background: var(--ca-card);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  color: var(--ca-ink);
  text-align: left;
  cursor: pointer;
}
/* A padlock, inline so it needs no icon font and no extra request. */
.ca-locked.ca-locked::before {
  content: "";
  flex: none;
  width: 15px;
  height: 15px;
  background: currentColor;
  opacity: 0.75;
  -webkit-mask: var(--ca-lock) center / contain no-repeat;
  mask: var(--ca-lock) center / contain no-repeat;
  --ca-lock: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z'/%3E%3C/svg%3E");
}
.ca-locked.ca-locked:hover, .ca-locked.ca-locked:focus-visible {
  border-color: var(--ca-accent);
  color: var(--ca-accent);
}

.ca-linkish.ca-linkish {
  padding: 0.6rem 0;
  border: 0;
  background: none;
  color: var(--ca-accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.ca-linkish.ca-linkish:hover, .ca-linkish.ca-linkish:focus-visible { border-color: transparent; }

.ca-lock-copy[hidden] { display: none; }

/* ------------------------------------------------------------------------- the CTA */
.ca-cta.ca-cta {
  display: inline-block;
  padding: 0.72rem 1.6rem;
  border: 0;
  border-radius: 100px;
  background: var(--ca-accent);
  color: var(--e-global-color-cd2d769, #fff);
  font-family: "DM Sans", Sans-serif;
  font-size: 17px;
  font-weight: 600;
  line-height: 26px;
  cursor: pointer;
}
.ca-cta.ca-cta:hover { filter: brightness(1.08); }
.ca-cta.ca-cta[disabled] { opacity: 0.55; cursor: progress; }

.ca-ghost.ca-ghost {
  padding: 0.72rem 1.4rem;
  border: 1px solid var(--ca-accent);
  border-radius: 100px;
  background: transparent;
  color: var(--ca-accent);
  font-family: "DM Sans", Sans-serif;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
}

/* ------------------------------------------------------------------- the pinned bar */
/* The draft asks for the preview banner to be visible at all times. A bar pinned to the top
   would fight the site header, which is itself sticky and hides on scroll, so this one sits at
   the bottom and carries only the price and the CTA — no sentence of the copy is repeated. */
.ca-bar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 90;
  padding: 0.7rem 0;
  padding-bottom: max(0.7rem, env(safe-area-inset-bottom));
  background: #fff;
  border-top: 1px solid var(--ca-line);
  box-shadow: 0 -8px 24px -20px rgba(21, 47, 78, 0.7);
}
.ca-bar[hidden] { display: none; }
.ca-bar-inner {
  display: flex;
  gap: 1rem;
  align-items: center;
  justify-content: space-between;
  max-width: 62rem;
  margin: 0 auto;
  padding: 0 1.2rem;
  font-family: "DM Sans", Sans-serif;
}
.ca-bar-price { margin: 0; font-size: 15px; line-height: 22px; color: #16202e; }
.ca-bar-price strong { font-family: "Poppins", Sans-serif; font-size: 21px; }
.ca-bar-price span { display: block; font-size: 13px; color: #5a6b80; }

/* the bar must not sit on top of the footer's last line */
body { padding-bottom: 84px; }

/* ----------------------------------------------------------------------- the modal */
.ca-modal {
  width: min(34rem, calc(100vw - 2rem));
  padding: 1.6rem 1.7rem 1.5rem;
  border: 0;
  border-radius: 18px;
  background: #fff;
  color: #16202e;
  font-family: "DM Sans", Sans-serif;
  font-size: 16.5px;
  line-height: 26px;
  box-shadow: 0 30px 60px -30px rgba(21, 47, 78, 0.75);
}
.ca-modal::backdrop { background: rgba(16, 54, 99, 0.45); }
.ca-modal .ca-h3 { margin: 0.5rem 0 0.7rem; font-size: 21px; line-height: 28px; }
.ca-modal .ca-prose p { margin: 0 0 0.8rem; }
.ca-modal .ca-prose p:last-child { margin-bottom: 0; }

.ca-modal-x.ca-modal-x {
  position: absolute;
  top: 0.6rem;
  right: 0.7rem;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: #5a6b80;
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
}
.ca-modal-x.ca-modal-x:hover { background: #f1f4f8; color: #16202e; }

.ca-modal-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 0.8rem;
  align-items: center;
  margin-top: 1.3rem;
}

/* ------------------------------------------------------------------------ phone */
@media (max-width: 767px) {
  .ca { padding: 22px 0 28px; font-size: 16px; line-height: 25px; }
  .ca-h2 { font-size: 24px; line-height: 31px; }
  .ca-h3 { font-size: 20px; line-height: 27px; }
  .ca-steps { grid-template-columns: 1fr; gap: 0.7rem; }
  .ca-grid2, .ca-kidages { grid-template-columns: 1fr; }
  .ca-section { padding: 1.2rem 1.1rem; }
  .ca-preview { padding: 1rem 1.1rem; }
  .ca-preview-actions { width: 100%; }
  .ca-actions .ca-locked.ca-locked { width: 100%; }
  .ca-choice { grid-template-columns: 1fr; }
  .ca-statepicker { margin-top: -0.6rem; }
  .ca-seg { width: 100%; }
  .ca-segbtn.ca-segbtn { flex: 1 1 0; }
  .ca-tabs { flex-wrap: nowrap; }
  .ca-tab.ca-tab { flex: 1 1 0; padding: 0.55rem 0.4rem 0.7rem; font-size: 14.5px; }
  .ca-buyrow { align-items: stretch; }
  .ca-buyrow .ca-cta { width: 100%; }
  .ca-bar-inner { padding: 0 1rem; gap: 0.8rem; }
  .ca-bar-price span { display: none; }
  .ca-modal-actions .ca-cta, .ca-modal-actions .ca-ghost { width: 100%; }
  body { padding-bottom: 76px; }
}

/* ========================================================================================
 * THE CARD GRID AND THE PAGES UNDER IT
 *
 * Pol: "the client area is very long and verbose. I was imagining bigger cards with images and
 * titles." So /tu-viaje/ is a grid of five cards and each one opens a real page. Detail is
 * a PAGE and not a modal because this is reference content that should be indexable and
 * shareable, and a modal has no URL for either. Modals stay for actions, which is what they
 * were for.
 * ======================================================================================== */

/* The purchase CTA is an <a> now, not a <button>, because on a detail page there is no form to
 * scroll to and it has to be able to navigate. .ca-cta already sets its own background and
 * colour, so the only thing a link needs on top is the underline off. */
.ca-cta.ca-cta { text-decoration: none; }

/* Only in .ca-sr, for the per-cell "Añadir desayuno del día 2" that makes nine identical
 * buttons distinguishable to a screen reader and to the modal title. */
.ca-sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------------------- sub-navigation */
.ca-subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.4rem;
  align-items: baseline;
  margin: 0 0 1.6rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--ca-line);
  font-size: 15px;
}
.ca-back {
  font-weight: 600;
  color: var(--ca-accent);
  text-decoration: none;
}
.ca-back::before { content: "\2190\00a0"; }
.ca-back:hover { text-decoration: underline; }
.ca-subnav-links { display: flex; flex-wrap: wrap; gap: 0.3rem 1.1rem; }
.ca-subnav-links a { color: var(--ca-muted); text-decoration: none; }
.ca-subnav-links a:hover { color: var(--ca-ink); }
/* Which one is current comes from one attribute the page sets, so the part stays shared. */
.ca-subnav[data-here="comida"] a[href$="/comida/"],
.ca-subnav[data-here="atracciones"] a[href$="/atracciones/"],
.ca-subnav[data-here="espectaculos"] a[href$="/espectaculos/"],
.ca-subnav[data-here="alojamiento"] a[href$="/alojamiento/"],
.ca-subnav[data-here="grupo"] a[href$="/grupo/"] {
  color: var(--ca-ink);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--ca-accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}

/* -------------------------------------------------------------------------- the cards */
.ca-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  margin-top: 1.3rem;
}
/* Five cards into three columns leaves a hole. Comida takes two, which is also the honest
   ranking: it is the only section with a deadline attached to it. */
.ca-card:first-child { grid-column: span 2; }

.ca-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--ca-line);
  border-radius: 16px;
  background: var(--ca-card);
  color: inherit;
  text-decoration: none;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.ca-card:hover, .ca-card:focus-visible {
  transform: translateY(-2px);
  border-color: var(--ca-accent);
  box-shadow: 0 16px 32px -26px rgba(21, 47, 78, 0.8);
}

/* The photography is not shot yet. Rather than borrow a stock castle that has nothing to do
   with the section, each card carries a coloured panel, a line drawing of the subject and a
   chip that says a photo is coming - the same rule as the .ca-slot chips: name what is
   missing, never fake it. Swapping in a real photo is one background-image rule per
   [data-art] value and no markup changes at all. */
.ca-card-art {
  position: relative;
  display: block;
  height: 168px;
  background: linear-gradient(135deg, #6b7c93, #2f3b4c);
}
.ca-card-art::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.55;
  background-position: center;
  background-repeat: no-repeat;
  background-size: 76px 76px;
}
.ca-card-art-note {
  position: absolute;
  right: 0.6rem;
  bottom: 0.6rem;
  padding: 0.1rem 0.5rem 0.15rem;
  border: 1px dashed rgba(255, 255, 255, 0.8);
  border-radius: 999px;
  color: #fff;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.ca-card-art[data-art="comida"] { background: linear-gradient(135deg, #c2410c, #7c2d12); }
.ca-card-art[data-art="comida"]::after {
  background-image: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'><path d='M6 3v5a2 2 0 0 0 4 0V3'/><path d='M8 10v11'/><path d='M17 12c-1.7 0-3-1.8-3-4s1.3-4 3-4 3 1.8 3 4-1.3 4-3 4Z'/><path d='M17 12v9'/></svg>");
}
.ca-card-art[data-art="atracciones"] { background: linear-gradient(135deg, #9108dc, #4c1d95); }
.ca-card-art[data-art="atracciones"]::after {
  background-image: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='10' r='7'/><path d='M12 3v14M5 10h14M7.05 5.05l9.9 9.9M16.95 5.05l-9.9 9.9'/><path d='M9 22l3-5 3 5'/></svg>");
}
.ca-card-art[data-art="espectaculos"] { background: linear-gradient(135deg, #1d4ed8, #172554); }
.ca-card-art[data-art="espectaculos"]::after {
  background-image: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='3'/><path d='M12 2v3M12 19v3M2 12h3M19 12h3M4.9 4.9l2.1 2.1M17 17l2.1 2.1M19.1 4.9L17 7M7 17l-2.1 2.1'/></svg>");
}
.ca-card-art[data-art="alojamiento"] { background: linear-gradient(135deg, #0f766e, #134e4a); }
.ca-card-art[data-art="alojamiento"]::after {
  background-image: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'><path d='M2 19v-7h13a5 5 0 0 1 5 5v2'/><path d='M2 19h20'/><path d='M2 12V6'/><path d='M6 12v-1.5A1.5 1.5 0 0 1 7.5 9h2A1.5 1.5 0 0 1 11 10.5V12'/></svg>");
}
.ca-card-art[data-art="grupo"] { background: linear-gradient(135deg, #b45309, #78350f); }
.ca-card-art[data-art="grupo"]::after {
  background-image: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'><circle cx='9' cy='7.5' r='3.2'/><path d='M3.2 20a5.8 5.8 0 0 1 11.6 0'/><circle cx='17.6' cy='11' r='2.3'/><path d='M16.6 20a4.6 4.6 0 0 1 4.6-4.6'/></svg>");
}

.ca-card-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.35rem;
  padding: 1rem 1.2rem 1.2rem;
}
.ca-card-title {
  font-family: "Poppins", Sans-serif;
  font-size: 20px;
  font-weight: 600;
  color: var(--e-global-color-8cd1398, #000);
}
.ca-card-text { font-size: 15.5px; line-height: 24px; color: var(--ca-muted); }
.ca-card-body::after {
  content: "\2192";
  margin-top: auto;
  padding-top: 0.6rem;
  color: var(--ca-accent);
  font-weight: 700;
}

/* --------------------------------------------------------------- blocks, strips, leads */
.ca-block { margin: 0 0 1.6rem; }
.ca-block .ca-h2 { margin-bottom: 0.5rem; }
.ca-lead { color: var(--ca-muted); }

/* A strip is a section that turned out to be one fact and one button. Two of them replaced
   two full sections of prose on the grid page. */
.ca-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem 1.5rem;
  align-items: center;
  justify-content: space-between;
  margin: 0 0 1.2rem;
  padding: 1.1rem 1.4rem;
  border: 1px solid var(--ca-line);
  border-radius: 16px;
  background: var(--ca-card);
}
.ca-strip-main { flex: 1 1 24rem; min-width: 0; }
.ca-strip .ca-h3 { margin-bottom: 0.5rem; }
.ca-strip .ca-actions { margin-top: 0; align-items: center; }
.ca-strip .ca-prose { font-size: 16px; line-height: 25px; color: var(--ca-muted); }

/* ---------------------------------------------------------------------- fact lists */
.ca-factlist {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.ca-factlist li {
  margin: 0;
  padding: 0.3rem 0.75rem 0.35rem;
  border: 1px solid var(--ca-line);
  border-radius: 999px;
  background: #fbfcfd;
  font-size: 14.5px;
  line-height: 22px;
}
.ca-fact-k { color: var(--ca-muted); }
.ca-fact-k::after { content: ":"; }
.ca-facts-grid .ca-factlist li { font-weight: 600; }

/* ------------------------------------------------------------- the reservations grid */
/* Days down, meals across. UNIQUE (trip_id, reservation_date, meal) in db/003_intake.sql is
   exactly what one cell expresses, so the grid cannot describe a state the database would
   refuse. It also shows the GAPS, which a list of what has been added structurally cannot. */
.ca-matrix-legend {
  margin: 1.1rem 0 0.6rem;
  font-size: 14.5px;
  line-height: 24px;
  color: var(--ca-muted);
}
.ca-matrix { display: grid; gap: 0.5rem; }
.ca-matrix-head, .ca-matrix-row {
  display: grid;
  grid-template-columns: minmax(8rem, 1.15fr) repeat(3, 1fr);
  gap: 0.5rem;
}
.ca-matrix-head span {
  padding-left: 0.2rem;
  font-size: 13px;
  font-weight: 600;
  color: var(--ca-muted);
}
.ca-matrix-day {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  justify-content: center;
  align-items: flex-start;
  padding: 0.5rem 0.2rem;
  font-size: 15px;
}
.ca-matrix-cell {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  justify-content: center;
  min-height: 64px;
  padding: 0.5rem;
  border: 1px dashed var(--ca-line);
  border-radius: 12px;
  background: #fbfcfd;
}
/* The meal name is in every cell for the phone, where the column headers are gone. On a wide
   screen the header says it once and this is hidden - no copy is duplicated in a content file
   or in the script to make the two layouts work. */
.ca-matrix-meal { display: none; font-size: 13.5px; font-weight: 600; color: var(--ca-muted); }
.ca-add.ca-add {
  width: 100%;
  justify-content: center;
  padding: 0.42rem 0.6rem;
  border-style: dashed;
  font-size: 14px;
}
.ca-matrix-more { grid-template-columns: 1fr; }
.ca-matrix-more .ca-matrix-day {
  padding-top: 0.2rem;
  font-size: 14px;
  color: var(--ca-muted);
}

/* --------------------------------------------------------------------------- posts */
.ca-posts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr));
  gap: 1rem;
  margin-top: 1.1rem;
}
.ca-post {
  position: relative;
  padding: 1.1rem 1.2rem 1.2rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  background: var(--ca-card);
}
.ca-post-title {
  margin: 0 0 0.4rem;
  font-family: "Poppins", Sans-serif;
  font-size: 17px;
  line-height: 25px;
  font-weight: 600;
  color: var(--e-global-color-8cd1398, #000);
}
.ca-post-text { margin: 0; font-size: 15px; line-height: 23px; color: var(--ca-muted); }
.ca-pending {
  display: inline-block;
  margin: 0 0 0.5rem;
  padding: 0.1rem 0.6rem 0.15rem;
  border: 1px dashed var(--ca-muted);
  border-radius: 999px;
  color: var(--ca-muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* ------------------------------------------------------- Extra Magic Time, the two sides */
/* The rule shown as its two outcomes rather than as a dismissible warning. Nothing here takes
   input: this is the logged-out page and there is no write path, and a control that accepts an
   answer and drops it is worse than one that says no. */
.ca-emh { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 1.2rem 0 0; }
.ca-emh-col {
  padding: 1.1rem 1.2rem 1.2rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  background: #fbfcfd;
  font-size: 15.5px;
  line-height: 24px;
}
.ca-emh-col[data-emh="yes"] { border-color: var(--ca-accent); background: rgba(145, 8, 220, 0.04); }
.ca-emh-col p { margin: 0 0 0.6rem; }
.ca-emh-col p:last-child { margin-bottom: 0; }
.ca-emh-title {
  margin: 0 0 0.5rem;
  font-family: "Poppins", Sans-serif;
  font-size: 17px;
  font-weight: 600;
  color: var(--e-global-color-8cd1398, #000);
}
.ca-emh-who { font-weight: 600; color: var(--ca-ink); }

/* A rule we apply, stated where it applies. Heavier than a note and lighter than a warning:
   it is not an alarm, it is how the question is ordered and why. */
.ca-rule {
  margin: 1.2rem 0 0;
  padding: 0.9rem 1.1rem;
  border-left: 4px solid var(--ca-accent);
  border-radius: 0 12px 12px 0;
  background: rgba(145, 8, 220, 0.05);
  font-size: 15.5px;
  line-height: 25px;
}
.ca-rule p { margin: 0 0 0.7rem; }
.ca-rule p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------- why we ask ages and heights */
/* Five reasons, and it is five because there are five things an age and a height decide. A
   repeat(auto-fit, …) track packed them 4 + 1 and left a hole; six sixths with the last two
   items taking three each reads as 3 + 2. Tied to the count on purpose — the count is the
   content here, not an accident of how many fitted. */
.ca-why {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 0.8rem;
  margin: 1.2rem 0 0;
}
.ca-why-item { grid-column: span 2; }
.ca-why-item:nth-child(4), .ca-why-item:nth-child(5) { grid-column: span 3; }
.ca-why-item {
  padding: 0.9rem 1rem 1rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  background: #fbfcfd;
}
.ca-why-item p { margin: 0; font-size: 14.5px; line-height: 23px; color: var(--ca-muted); }
.ca-why-title {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0 0 0.4rem;
  font-family: "Poppins", Sans-serif;
  font-size: 16px;
  font-weight: 600;
  color: var(--e-global-color-8cd1398, #000);
}
.ca-why-title::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  background: var(--ca-accent);
  -webkit-mask: var(--ca-why-icon) center / contain no-repeat;
  mask: var(--ca-why-icon) center / contain no-repeat;
}
.ca-why-item[data-why="intensity"] .ca-why-title {
  --ca-why-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M2 18c3 0 4-12 8-12s5 8 8 8 3-4 4-4'/></svg>");
}
.ca-why-item[data-why="height"] .ca-why-title {
  --ca-why-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M5 21V3M19 21V3M5 8h4M5 13h4M5 18h4'/></svg>");
}
.ca-why-item[data-why="babyswitch"] .ca-why-title {
  --ca-why-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4 8h13l-3-3M20 16H7l3 3'/></svg>");
}
.ca-why-item[data-why="singlerider"] .ca-why-title {
  --ca-why-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='6.5' r='3'/><path d='M6 21a6 6 0 0 1 12 0'/></svg>");
}
.ca-why-item[data-why="stroller"] .ca-why-title {
  --ca-why-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4 4h2l2 8h11a7 7 0 0 1-7 6h-2a4 4 0 0 1-4-4'/><circle cx='9' cy='20' r='1.5'/><circle cx='17' cy='20' r='1.5'/></svg>");
}

/* ------------------------------------------------------------------- the height table */
.ca-heights { margin: 1.3rem 0 0.6rem; overflow-x: auto; }
.ca-heights table { width: 100%; border-collapse: collapse; font-size: 15px; }
.ca-heights th, .ca-heights td {
  padding: 0.55rem 0.7rem;
  border-bottom: 1px solid var(--ca-line);
  text-align: left;
  vertical-align: top;
}
.ca-heights th {
  font-family: "DM Sans", Sans-serif;
  font-size: 13px;
  font-weight: 600;
  color: var(--ca-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.ca-heights td:first-child {
  width: 7.5rem;
  font-family: "Poppins", Sans-serif;
  font-weight: 600;
  color: var(--ca-accent);
  white-space: nowrap;
}
.ca-heights-note { margin: 0; font-size: 14px; line-height: 22px; color: var(--ca-muted); }

/* -------------------------------------------------------------- the detail-page CTA */
.ca-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  align-items: center;
  justify-content: space-between;
  margin: 2rem 0 0;
  padding: 1.2rem 1.4rem;
  border: 1px solid var(--ca-accent);
  border-radius: 16px;
  background: var(--ca-card);
}
.ca-foot-text { flex: 1 1 22rem; font-size: 15.5px; line-height: 25px; color: var(--ca-muted); }
.ca-foot-text p { margin: 0; }

/* The purchase form is a dialog now and it is on all six pages, so #ca-form no longer says
   anything about whether this page has a pinned bar. #ca-bar does. */
body:not(:has(#ca-bar)) { padding-bottom: 0; }

/* ------------------------------------------------------------------------ phone */
@media (max-width: 767px) {
  .ca-cards { grid-template-columns: 1fr; }
  .ca-card:first-child { grid-column: auto; }
  .ca-card-art { height: 140px; }
  .ca-card-title { font-size: 18px; }

  .ca-subnav { gap: 0.5rem 1rem; }
  .ca-subnav-links { gap: 0.25rem 0.9rem; font-size: 14px; }

  /* The matrix restacks: one card per day, three labelled slots inside it. Same markup - the
     per-cell meal name that desktop hides is what carries the phone layout. Three columns is
     the most a matrix can have here and it will never grow, which is why the shape survives
     a phone at all; a matrix that got wider would not. */
  .ca-matrix { gap: 0.7rem; }
  .ca-matrix-head { display: none; }
  .ca-matrix-row {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 0.6rem 0.9rem 0.8rem;
    border: 1px solid var(--ca-line);
    border-radius: 14px;
    background: var(--ca-card);
  }
  /* justify-content is the cross axis no longer: the base rule centres a column, and once the
     direction flips to row that same rule centres the day label horizontally. */
  .ca-matrix-day {
    flex-direction: row;
    justify-content: flex-start;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.1rem 0 0.4rem;
  }
  .ca-matrix-cell {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 0.8rem;
    min-height: 0;
    padding: 0.5rem 0;
    border: 0;
    border-top: 1px dashed var(--ca-line);
    border-radius: 0;
    background: transparent;
  }
  .ca-matrix-meal { display: block; }
  .ca-add.ca-add { width: auto; flex: none; }
  .ca-matrix-more {
    padding: 0;
    border: 0;
    background: transparent;
  }
  .ca-matrix-more .ca-matrix-day { padding: 0; }

  .ca-emh { grid-template-columns: 1fr; }
  .ca-why { grid-template-columns: 1fr; }
  .ca-why-item, .ca-why-item:nth-child(4), .ca-why-item:nth-child(5) { grid-column: auto; }
  .ca-posts { grid-template-columns: 1fr; }
  .ca-strip { padding: 1rem 1.1rem; }
  .ca-strip .ca-actions { width: 100%; }
  .ca-foot { padding: 1.1rem; }
  .ca-foot .ca-cta { width: 100%; text-align: center; }
  .ca-heights td:first-child { width: 5.5rem; }
}

/* ========================================================================================
 * EDITABLE FIRST
 *
 * Pol: "Inside the sections, the lock and CTA should be in the editable bits: reservations,
 * party heights and ages, must sees, etc. That should always be the first block. The rest
 * should allow the customer to gather information so they can decide better on those editable
 * ones." So every section page opens with .ca-editable and everything under it is reading
 * matter. These rules are what make the two halves look like two halves.
 * ======================================================================================== */

/* A heading and its step or section tag, as one unit, so .ca-section-head can keep pushing the
   badge to the far end. Without the wrapper, space-between puts the tag, the title and the
   badge at three different edges. */
.ca-section-title { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.ca-step-tag {
  font-family: "DM Sans", Sans-serif;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ca-accent);
}
.ca-section-title .ca-h2, .ca-section-title .ca-h3 { margin: 0; }

/* The first block on the page is the one the visitor is meant to act on, so it is the only
   block with the accent edge. Everything below it is white on the same page background. */
.ca-editable {
  border-color: var(--ca-accent);
  box-shadow: 0 14px 34px -26px rgba(21, 47, 78, 0.6);
}
body[data-ca-state="locked"] .ca-editable { box-shadow: none; }

/* The bridge sentence between the editable block and the reading matter. */
.ca-infolead { margin: 1.6rem 0 1.2rem; }
/* Two lead paragraphs in a row - the page's own bridge line and the shared "the posts are
   being written" note - would otherwise touch, because .ca-prose zeroes the last margin. */
.ca-lead + .ca-lead { margin-top: 0.9rem; }
/* Same reason, for an information block built from two content values in a row - the shows page
   puts the nightly-show paragraph and the parade paragraph next to each other. */
.ca-block .ca-prose + .ca-prose { margin-top: 0.9rem; }

/* ------------------------------------------------------------------- the locked preview */
/* Pol: "Editable blocks should either be the title, or a preview of filled content (as an
   example) that cannot be edited (with a lock and if clicked pop up to CTA)."
   .ca-lockpad is that second treatment. It carries data-lock itself, and the script delegates
   with closest, so a click anywhere in it that is not already a button opens the same modal -
   no extra JavaScript, and no invisible overlay stealing the real buttons' pointer events. It
   is not focusable: the controls inside it are, and they are the accessible path to the same
   modal. */
.ca-lockpad {
  position: relative;
  margin-top: 1.2rem;
  padding: 1rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  /* The hatch is the signal that this is an example and not a state. It is a gradient, not an
     image, so it costs no request and follows the accent colour. */
  background:
    repeating-linear-gradient(135deg, rgba(145, 8, 220, 0.045) 0 10px, transparent 10px 20px),
    #fdfdff;
  cursor: pointer;
}
.ca-lockpad:hover { border-color: var(--ca-accent); }

/* Said in words as well as in hatching, because a pattern is not a sentence. In flow rather
   than absolutely positioned: this string is the longest thing in the block and it has to be
   free to wrap to two lines in ca/en/fr without landing on top of the key below it. */
.ca-example-tag {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 0.7rem;
  font-family: "DM Sans", Sans-serif;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ca-accent);
}
.ca-example-tag::before {
  content: "";
  flex: none;
  align-self: flex-start;
  margin-top: 0.25rem;
  width: 13px;
  height: 13px;
  background: currentColor;
  -webkit-mask: var(--ca-lock) center / contain no-repeat;
  mask: var(--ca-lock) center / contain no-repeat;
  --ca-lock: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------- the four kinds of meal in a cell */
/* Pol: "The matrix could display the reservations with a lock or some other signal and the rest
   with the recommended restaurants... it could include lunch in the hotel, or bring your own
   sandwich to show diversity and richness of planning." The distinction between a table the
   customer booked and a place we suggested is the product, so it is the loudest thing in the
   grid: colour, tag, and whether there is a Cambiar button at all. */
.ca-matrix-key {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1rem;
  margin: 0 0 0.8rem;
  padding: 0;
  list-style: none;
  font-size: 13.5px;
  color: var(--ca-muted);
}
.ca-matrix-key li { display: flex; align-items: center; gap: 0.4rem; }
.ca-key-swatch {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 4px;
  border: 1px solid var(--ca-line);
  background: #fbfcfd;
}
.ca-key-swatch[data-kind="reserva"] { border-color: #152f4e; background: rgba(21, 47, 78, 0.12); }
.ca-key-swatch[data-kind="sugerida"] { border-color: var(--ca-accent); background: rgba(145, 8, 220, 0.1); }
.ca-key-swatch[data-kind="hotel"] { border-color: #0f766e; background: rgba(15, 118, 110, 0.12); }
.ca-key-swatch[data-kind="fuera"] { border-color: #b45309; background: rgba(180, 83, 9, 0.12); }
.ca-key-swatch[data-kind="libre"] { border-style: dashed; }

.ca-matrix-filled {
  align-items: flex-start;
  gap: 0.15rem;
  border-style: solid;
  background: #fff;
}
.ca-cell-kind {
  font-family: "DM Sans", Sans-serif;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.ca-cell-what { font-size: 14.5px; font-weight: 600; line-height: 20px; color: var(--ca-ink); }
.ca-cell-when { font-size: 13px; line-height: 19px; color: var(--ca-muted); }

/* The alternative half of a paired cell. A packed lunch is never shown on its own - see the
   comment in tu-viaje-comida.html. It reads as a second, lighter line under the
   recommendation so the pair says "here, or this instead", not "we had nothing for you". */
.ca-cell-alt {
  display: block;
  margin-top: 5px;
  padding-top: 5px;
  border-top: 1px dashed var(--ca-line);
  font-size: 12.5px;
  line-height: 17px;
  color: var(--ca-muted);
}
.ca-cell-or {
  font-weight: 700;
  font-style: italic;
  margin-right: 2px;
  color: var(--ca-ink);
}

/* ------------------------------------------------------------------ cell icons
   Pol: "no 'os proponemos', and this kind of types... Icon to change if possible,
   restaurant and time." With the kind words gone, three things carry the meaning:
   a pencil = we suggested this and it can be swapped; a plus = nothing here yet;
   a bookmark = the customer's own booking, which has NO control because it is not
   ours to change. Every icon keeps a .ca-sr label, so the grid still reads aloud as
   "Vuestra reserva: restaurante" / "Cambiar Comida Día 1". */
.ca-i {
  width: 15px; height: 15px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.ca-i-book {
  width: 13px; height: 13px;
  fill: currentColor; stroke: none;
  margin-right: 5px; vertical-align: -1px;
}
.ca-matrix-cell .ca-cell-edit,
.ca-matrix-cell .ca-add {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0;
  border-radius: 999px;
  line-height: 0;
}
.ca-matrix-cell .ca-cell-edit { position: absolute; top: 6px; right: 6px; }
.ca-matrix-cell { position: relative; }
.ca-cell-what { padding-right: 26px; }

/* Tighter cards. The kind line is gone, so a filled cell is two lines - name, hour -
   and the box should not keep the height it needed for three. */
.ca-matrix-cell.ca-matrix-filled { padding: 9px 10px; }
.ca-cell-what { font-size: 14px; line-height: 18px; }
.ca-cell-when { font-size: 12.5px; line-height: 17px; font-variant-numeric: tabular-nums; }

/* ------------------------------------------------- the grid stays a grid on a phone
   Pol: "don't the three columns fit in the phone view? ... try with full width."
   Pol, 26 August 2026: "the reservation block is overflowing the section, make it tighter."

   BOTH OF THOSE ARE HONOURED HERE, and the second one overturned the first's mechanism.
   The three columns did not fit at 390 because the grid was living inside 116px of
   inherited padding - 58.5px of Elementor's container margin, 35px of section padding and
   22px of lockpad - which left each meal column 64px, not enough for "Agrabah Café
   Restaurant". The fix then was 100vw with a calc() pull, which is immune to any ancestor's
   padding because it steps OUTSIDE it. It bought ~110px columns and it did so by breaking
   out of the section: measured at 390 on 26 August, .ca-matrix ran 0 -> 390 while the
   section ran 29 -> 361, so the day cards hung 48px past the border on both sides.

   So the padding is taken off the CONTAINERS instead of escaped. Section padding drops to
   12px and .ca-resbox to 8px for this block only, which leaves ~85px per column at 390 -
   less than the bleed bought, and inside the box, which is what was asked for. The columns
   hold what they now have to hold: an empty cell is a plus, and a filled one is the
   customer's own venue name, which wraps. */
@media (max-width: 767px) {
  #ca-reservations { padding-left: 12px; padding-right: 12px; }
  #ca-reservations .ca-resbox { padding-left: 8px; padding-right: 8px; }

  .ca-matrix {
    gap: 4px;
  }
  .ca-matrix-head,
  .ca-matrix-row {
    display: grid;
    grid-template-columns: 24px repeat(3, 1fr);
    gap: 4px;
    align-items: stretch;
  }
  .ca-matrix-head { display: grid; font-size: 10.5px; }
  .ca-matrix-head span { padding: 0 2px; }

  /* The day label turns on its side: it is two characters, and a horizontal one would
     cost a column the restaurants need more. */
  .ca-matrix-day {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    display: flex; align-items: center; justify-content: center;
    padding: 2px; font-size: 10.5px; line-height: 1;
  }
  .ca-matrix-day .ca-slot,
  .ca-matrix-day .ca-matrix-date { display: none; }

  /* ...but the closing "one row per day of your trip" note is a sentence, not a label.
     Turning that on its side made it 600px tall and was most of the grid's height. */
  .ca-matrix-more .ca-matrix-day {
    writing-mode: horizontal-tb;
    transform: none;
    display: block;
    text-align: center;
    font-size: 12px;
    line-height: 1.4;
    padding: 6px 8px;
  }

  /* The column header already names the meal, so the per-cell label is redundant here. */
  .ca-matrix-meal { display: none; }

  /* One icon per cell. The pencil already says "this is ours and it can change"; the
     generic lock glyph on every .ca-locked control is right in a row of wide buttons and
     just noise in a 102px cell that is already inside a locked pad. */
  .ca-matrix-cell .ca-locked.ca-locked::before { display: none; }

  /* BACK TO A COLUMN. The 1023px restack turns a cell into a ROW - name and hour side by
     side - because there it is a full-width line inside a per-day card. Three columns is the
     opposite shape and this block never undid it, so a 74px cell was laying "Café Hyperion"
     and "13:15" out horizontally and spilling 40px into its neighbour. Measured at 390 on
     26 August 2026: scrollWidth 114 against clientWidth 74, and the overlap was visible.
     min-width:0 is what lets a grid item shrink below its content at all; without the
     direction reset it only decided WHERE the overflow went. */
  .ca-matrix-cell {
    min-width: 0;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 2px;
  }
  .ca-cell-what, .ca-cell-when, .ca-cell-alt {
    min-width: 0;
    overflow-wrap: break-word;
    hyphens: none;
  }
  /* A .ca-slot chip has padding and a border and does not wrap, so at this width it is the one
     thing in the grid that cannot be made to fit by shrinking type. It is allowed to break. */
  .ca-matrix-cell .ca-slot {
    max-width: 100%;
    overflow-wrap: break-word;
    white-space: normal;
  }
  .ca-matrix-cell.ca-matrix-filled { padding: 7px 6px; }
  .ca-cell-what {
    font-size: 11.5px; line-height: 14.5px; padding-right: 0;
    /* break-word, NOT anywhere: "anywhere" split Café Hyperion into "Caf é Hy peri on".
       Long names should wrap between words and only break as a last resort. */
    overflow-wrap: break-word;
    hyphens: none;
  }
  .ca-cell-when { font-size: 11px; line-height: 14px; }
  .ca-cell-alt { font-size: 10.5px; line-height: 13px; margin-top: 4px; padding-top: 4px; }
  .ca-cell-or { margin-right: 1px; }

  /* Static, not absolute: at this width an overlaid button would sit on top of the name. */
  .ca-matrix-cell .ca-cell-edit {
    position: static; transform: none;
    width: 22px; height: 22px; margin-top: 4px;
  }
  /* An empty cell IS the control now - there is nothing else in it - so the plus fills the
     cell rather than sitting in the middle of it as a 26px dot. Same markup, a bigger
     target, which is the whole difference on a phone. */
  .ca-matrix-cell .ca-add { width: 100%; height: auto; min-height: 32px; }
  .ca-i { width: 13px; height: 13px; }

  .ca-matrix-more { grid-template-columns: 1fr; }
}

.ca-matrix-filled[data-kind="reserva"] { border-color: #152f4e; background: rgba(21, 47, 78, 0.05); }
.ca-matrix-filled[data-kind="reserva"] .ca-cell-kind { color: #152f4e; }
.ca-matrix-filled[data-kind="sugerida"] { border-color: var(--ca-accent); background: rgba(145, 8, 220, 0.05); }
.ca-matrix-filled[data-kind="sugerida"] .ca-cell-kind { color: var(--ca-accent); }
.ca-matrix-filled[data-kind="hotel"] { border-color: #0f766e; background: rgba(15, 118, 110, 0.05); }
.ca-matrix-filled[data-kind="hotel"] .ca-cell-kind { color: #0f766e; }
.ca-matrix-filled[data-kind="fuera"] { border-color: #b45309; background: rgba(180, 83, 9, 0.05); }
.ca-matrix-filled[data-kind="fuera"] .ca-cell-kind { color: #b45309; }

/* A booking of theirs is a fixed point; there is nothing to swap. A suggestion of ours can be
   changed for something nearby, and that button is the only place the difference is an action
   and not just a colour. */
.ca-cell-edit.ca-cell-edit {
  align-self: flex-start;
  margin-top: 0.25rem;
  padding: 0.22rem 0.6rem 0.22rem 0.5rem;
  border-style: dashed;
  font-size: 12.5px;
}
.ca-cell-edit.ca-cell-edit::before { width: 11px; height: 11px; }

/* --------------------------------------------- rows of answers, one per repeated thing */
/* Two blocks are the same idea and therefore the same rules: the per-day hours on
   /alojamiento/ (a day, an entry, an exit) and the party on /grupo/ (a person, an age, a
   height). Three columns, a label column and two value cells, and EVERY value is a dashed chip
   because all of them are the customer's own data and none of them is ours to guess. Same
   restack as the meals grid at 767px, one column narrower.

   They share the declarations rather than owning a copy each: two identical blocks drifting
   apart is how /alojamiento/ and /grupo/ would stop looking like one product. The class names
   stay per-block so the markup still says what it is. */
.ca-answers { margin: 0 0 1rem; }
.ca-hours, .ca-people { display: grid; gap: 0.5rem; }
.ca-hours-head, .ca-hours-row,
.ca-people-head, .ca-people-row {
  display: grid;
  grid-template-columns: minmax(8rem, 1.15fr) repeat(2, 1fr);
  gap: 0.5rem;
}
.ca-hours-head span,
.ca-people-head span {
  padding-left: 0.2rem;
  font-size: 13px;
  font-weight: 600;
  color: var(--ca-muted);
}
.ca-hours-day,
.ca-people-who {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  justify-content: center;
  /* Without this the chip stretches to the width of the column and stops reading as a chip. */
  align-items: flex-start;
  padding: 0.5rem 0.2rem;
  font-size: 15px;
}
.ca-hours-cell,
.ca-people-cell {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  justify-content: center;
  align-items: flex-start;
  min-height: 52px;
  padding: 0.5rem;
  border: 1px dashed var(--ca-line);
  border-radius: 12px;
  background: #fbfcfd;
}
.ca-hours-lbl,
.ca-people-lbl { display: none; font-size: 13.5px; font-weight: 600; color: var(--ca-muted); }
.ca-hours-more, .ca-people-more { grid-template-columns: 1fr; }
.ca-hours-more .ca-hours-day,
.ca-people-more .ca-people-who { padding-top: 0.2rem; font-size: 14px; color: var(--ca-muted); }

/* The line under the party rows. It carries the two facts the rows themselves cannot show -
   that nothing is pre-filled and that the list may stay empty - so it sits inside the pad,
   where someone counting the example rows is already looking. */
.ca-people-note {
  /* The hairline is what stops it merging with the "and one row per person" line above it:
     two muted paragraphs of the same size stacked with only a margin between them read as one
     paragraph, and at 390px they fill half the pad. */
  margin: 0.7rem 0 0;
  padding-top: 0.7rem;
  border-top: 1px dashed var(--ca-line);
  font-size: 14px;
  line-height: 22px;
  color: var(--ca-muted);
}

/* ------------------------------------------------------------------ the purchase dialog */
/* Pol: "It could fit in a page with two columns and two rows." One .ca-grid2 with four labels
   in it is exactly that, and it is the same class that already collapses to one column at
   767px - so the phone layout costs nothing. Wider than the lock modal because four fields
   next to each other need the room; still narrower than the page. */
.ca-modal-buy { width: min(42rem, calc(100vw - 2rem)); }
.ca-modal-buy .ca-h3 { margin-top: 0; padding-right: 2rem; }
.ca-modal-lead { margin-bottom: 1.2rem; font-size: 15.5px; line-height: 24px; color: var(--ca-muted); }
.ca-modal-buy .ca-grid2 { gap: 0.2rem 1.2rem; }
.ca-modal-buy .ca-buyrow { margin-top: 0.4rem; }
.ca-modal-buy .ca-gate { margin-bottom: 0.2rem; }

/* ======================================================================================== */
/* THE FOOTER COLOUR                                                                        */
/* Navy, #152F4E — --e-global-color-65e99da, a colour the kit already declares, so the palette
 * does not grow. Production paints this footer --e-global-color-356bd45, #FF5479, a hot pink
 * that is the loudest thing on the page once the client area's own purple accent is on screen
 * too. Navy is already this area's colour for "fixed / locked", and it leaves the purple CTA as
 * the only loud thing on the page.
 *
 * Chosen by Pol, August 2026, over the brand purple, which was the other candidate: a purple
 * footer competes with every CTA for the same attention. That option is gone rather than
 * commented out — a dead alternative in a stylesheet is a puzzle for whoever reads it next.
 *
 * Scoped to this stylesheet, which only loads on the six /tu-viaje/ pages, so the six
 * mirrored marketing pages keep production pink and this stays a test rather than a site-wide
 * change. Moving it site-wide is one line in assets/css/chrome.css.
 *
 * The specificity is deliberate: chrome.css sets the background at (0,4,0), so a plain class
 * loses to it however late this file loads.
 */
body .elementor .elementor-element.elementor-element-ed10813:not(.elementor-motion-effects-element-type-background) {
  background-color: var(--e-global-color-65e99da, #152f4e);
}

/* ------------------------------------------------------------------------------- phone */
@media (max-width: 767px) {
  .ca-lockpad { padding: 0.8rem 0.7rem; }
  .ca-example-tag { font-size: 11.5px; }
  .ca-matrix-key { font-size: 12.5px; gap: 0.3rem 0.8rem; }

  /* THE FILLED-CELL GRID USED TO BE HERE AND IT IS GONE, 26 August 2026.
     It said `display: grid; grid-template-columns: auto 1fr` with the meal name in column 1
     and everything else in column 2, and it was written for the layout where a phone got ONE
     CARD PER DAY and a cell was a full-width line inside it. That layout was replaced by three
     narrow columns further up this file - in an EARLIER @media (max-width: 767px) block, so
     this one won on order and quietly kept turning every cell back into a two-column grid with
     a 12.8px gutter it no longer had the width for.

     What that cost, measured at 390 on 26 August: "Café Hyperion" wrapped one character per
     line, and the cell overflowed its column by 40px into its neighbour. It also explains why
     the cell reported flex-direction: row - it was not a flex container at all, so that was
     just the initial value, and setting flex-direction on it did nothing.

     Nothing outside .ca-matrix uses .ca-matrix-filled, so these five rules had no other job. */

  .ca-hours-head, .ca-people-head { display: none; }
  .ca-hours-row, .ca-people-row {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 0.6rem 0.9rem 0.8rem;
    border: 1px solid var(--ca-line);
    border-radius: 14px;
    background: var(--ca-card);
  }
  .ca-hours-day,
  .ca-people-who { flex-direction: row; align-items: baseline; gap: 0.5rem; padding: 0.1rem 0 0.4rem; }
  .ca-hours-cell,
  .ca-people-cell {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    min-height: 0;
    padding: 0.5rem 0;
    border: 0;
    border-top: 1px dashed var(--ca-line);
    border-radius: 0;
    background: transparent;
  }
  .ca-hours-lbl, .ca-people-lbl { display: block; }
  .ca-hours-more, .ca-people-more { padding: 0; border: 0; background: transparent; }
  .ca-hours-more .ca-hours-day,
  .ca-people-more .ca-people-who { padding: 0; }

  .ca-modal-buy { width: calc(100vw - 1.4rem); padding: 1.3rem 1.1rem 1.2rem; }
  .ca-modal-buy .ca-buyrow .ca-cta { width: 100%; }
}

/* ========================================================================================
 * "NOTHING HERE" IS AN ANSWER
 *
 * Pol, August 2026: "all the options in the area de cliente should have an intentional blank
 * response. With that I mean: reservations, I don't have more/any reservations."
 *
 * Two visual jobs, and they are not the same job:
 *
 *   .ca-none*    the control itself, in the editable block. It has to look like something you
 *                DID, not like something you skipped - so the pressed state gets a filled tick,
 *                an accent edge, a Respondido chip, and a different sentence underneath. An
 *                unpressed one is deliberately quiet: it is an option, not an instruction.
 *   .ca-resumen* the completeness summary inside the lock modal, opened by the generate button.
 *
 * Neither of them is allowed to look like an error. There is no red anywhere in this block and
 * no count: everything the summary lists is optional, and a customer who generates with all of
 * it blank has done nothing wrong. --ca-bad is for the purchase form, and stays there.
 * ======================================================================================== */

.ca-nones {
  margin-top: 1.2rem;
  padding: 1rem 1.1rem 1.1rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  background: #fbfcfd;
}
.ca-nones-head {
  margin: 0 0 0.7rem;
  font-family: "DM Sans", Sans-serif;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ca-muted);
}
.ca-none + .ca-none { margin-top: 1rem; padding-top: 1rem; border-top: 1px dashed var(--ca-line); }

/* The control. A button and not a checkbox: the label is a whole sentence, the tick has to sit
   beside it rather than inside a <label>'s baseline, and the two states need a chip and an edge
   that a native box cannot carry. aria-pressed is what makes it a toggle to a screen reader,
   and it is what the stylesheet keys on, so the markup and the announcement cannot disagree. */
.ca-none-btn.ca-none-btn {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  width: 100%;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--ca-line);
  border-radius: 12px;
  background: #fff;
  font: inherit;
  font-size: 15.5px;
  line-height: 23px;
  font-weight: 600;
  color: var(--ca-ink);
  text-align: left;
  white-space: normal;
  cursor: pointer;
}
.ca-none-btn.ca-none-btn:hover,
.ca-none-btn.ca-none-btn:focus-visible { border-color: var(--ca-accent); }

/* The tick box, drawn rather than imaged: no extra request, and it follows the accent token. */
.ca-none-btn.ca-none-btn::before {
  content: "";
  flex: none;
  margin-top: 0.28rem;
  width: 18px;
  height: 18px;
  border: 1.5px solid #b9c4d2;
  border-radius: 5px;
  background: #fff no-repeat center / 12px 12px;
}
.ca-none-btn.ca-none-btn[aria-pressed="true"] {
  border-color: var(--ca-accent);
  background: rgba(145, 8, 220, 0.05);
}
.ca-none-btn.ca-none-btn[aria-pressed="true"]::before {
  border-color: var(--ca-accent);
  background-color: var(--ca-accent);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E");
}

.ca-none-label { flex: 1 1 auto; min-width: 0; }

/* The third signal, after the tick and the swapped paragraph. Three is not one too many: the
   whole point is that "answered: none" must be impossible to mistake for "untouched". */
.ca-none-tag {
  display: none;
  flex: none;
  align-self: flex-start;
  margin-top: 0.15rem;
  padding: 0.05rem 0.55rem 0.1rem;
  border-radius: 999px;
  background: var(--ca-accent);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  line-height: 20px;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.ca-none-btn.ca-none-btn[aria-pressed="true"] .ca-none-tag { display: inline-block; }

.ca-none-todo, .ca-none-done {
  margin: 0.5rem 0 0;
  padding-left: 2.15rem;      /* clears the tick box, so the two sentences line up under the label */
  font-size: 14.5px;
  line-height: 22px;
  color: var(--ca-muted);
}
.ca-none-done { color: var(--ca-ink); }
.ca-none-todo[hidden], .ca-none-done[hidden] { display: none; }

/* The closed list freezes the grid (28 Aug 2026): the checkbox is a state of the table, so the
   table shows it - controls out of reach, everything a shade quieter. The editor's click
   handler holds the keyboard half of the same rule. */
#ca-reservations[data-ca-res-frozen] [data-ca-matrix] { opacity: 0.5; filter: grayscale(1); }
#ca-reservations[data-ca-res-frozen] .ca-add,
#ca-reservations[data-ca-res-frozen] .ca-cell-edit { pointer-events: none; opacity: 0.3; }

/* The closed-list checkbox, on the grid it closes. Hidden while the grid is the example:
   there is no list to close yet. */
.ca-none-ingrid { margin-top: 0.9rem; }
#ca-reservations[data-ca-res="ejemplo"] .ca-none-ingrid { display: none; }

/* The two-way intolerances answer. The chips are native checkboxes dressed as pills - the
   vocabulary is short and flat, and a row of pills reads as "tick what applies" without a
   sentence of instructions. */
.ca-intol { margin-top: 1rem; padding-top: 1rem; border-top: 1px dashed var(--ca-line); }
.ca-intol-q { margin: 0 0 0.5rem; font-size: 15.5px; font-weight: 700; color: var(--ca-ink); }
.ca-intol .ca-none { margin-top: 0.6rem; padding-top: 0; border-top: 0; }
.ca-intol-yes.ca-intol-yes { margin-bottom: 0; }
.ca-intol-panel { margin: 0.7rem 0 0.2rem; padding: 0.8rem 0.9rem; border: 1px dashed var(--ca-line); border-radius: 12px; }
.ca-intol-panel[hidden] { display: none; }
.ca-intol-which { margin: 0 0 0.4rem; font-size: 14.5px; font-weight: 600; color: var(--ca-ink); }
.ca-intol-opts { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 0.7rem; }
.ca-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--ca-line);
  border-radius: 999px;
  background: #fff;
  font-size: 14px;
  line-height: 21px;
  color: var(--ca-ink);
  cursor: pointer;
}
.ca-chip input { accent-color: var(--ca-accent); margin: 0; }
.ca-chip:has(input:checked) { border-color: var(--ca-accent); background: rgba(145, 8, 220, 0.05); }
.ca-intol-consider { margin: 0 0 0.7rem; font-size: 14px; line-height: 21px; color: var(--ca-muted); }

/* The height-gate decision (#146, 29 Aug 2026). The list is GREY AND UNTOUCHABLE while the
   default stands, and it is the default's own honest picture of itself: the rides are visible,
   with the centimetres that removed them, and they are visibly not going anywhere the family
   has a say over until they press the other button. Same device as the frozen reservations
   grid above - opacity plus grayscale plus pointer-events - because it is the same statement.
   Grey is not a disabled control here; it is the answer.

   Which state is grey follows the DEFAULT and not a fixed mode: the expert's ruling put the
   default at 'include', and if it ever moved the grey moves with it. That is why the selectors
   below key off data-ca-hgate-editable, which the script writes from GATE_DEFAULT, rather than
   off data-ca-hgate-mode. */
.ca-hgate { margin-top: 1rem; padding-top: 1rem; border-top: 1px dashed var(--ca-line); }
.ca-hgate[hidden] { display: none; }
.ca-hgate-q { margin: 0 0 0.5rem; font-size: 15.5px; font-weight: 700; color: var(--ca-ink); }
.ca-hgate-why { margin-bottom: 0.7rem; }
.ca-hgate-wait,
.ca-hgate-note { margin: 0.6rem 0 0; font-size: 14px; line-height: 21px; color: var(--ca-muted); }
.ca-hgate-note[hidden] { display: none; }
.ca-hgate-live[hidden] { display: none; }
/* The default sentence sits between the explanation and the list, quieter than the
   question and heavier than the prose: it is the thing that happens if the visitor reads
   the block and walks away, which is most of them. */
.ca-hgate-default { margin: 0 0 0.7rem; font-size: 14px; line-height: 21px;
                    font-weight: 600; color: var(--ca-muted); }
.ca-hgate-count { margin: 0 0 0.6rem; font-size: 14.5px; font-weight: 600; color: var(--ca-ink); }
.ca-hgate-modes { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.7rem; }
.ca-hgate-mode.ca-hgate-mode { margin-bottom: 0; }

.ca-hgate-list { display: flex; flex-direction: column; gap: 0.4rem; }
.ca-hgate-item { align-items: baseline; border-radius: 12px; }
.ca-hgate-name { font-weight: 600; }
.ca-hgate-reason { color: var(--ca-muted); font-size: 13.5px; }

/* THE DEFAULT IS THE GREY ONE, whichever way the default points: data-ca-hgate-editable is
   written by the script from GATE_DEFAULT, so the stylesheet never has to know whether the
   default is include or skip. pointer-events off is the CSS half; the checkboxes carry a real
   disabled attribute too, so the keyboard tells the same story as the mouse. */
.ca-hgate[data-ca-hgate-editable="no"] .ca-hgate-list { opacity: 0.6; filter: grayscale(1); }
.ca-hgate[data-ca-hgate-editable="no"] .ca-hgate-item { pointer-events: none; }

/* The aside about single rider: present, quiet, and visibly not the recommendation. */
.ca-hgate-tip { margin: 0 0 0.7rem; font-size: 13.5px; line-height: 20px; color: var(--ca-muted); }

/* THE COIN FLIP AT THE GATE. A ride the shortest member clears by exactly zero is in the
   itinerary either way - so it has no checkbox - but on the day it is a person with a measuring
   stick who decides. Dashed rather than solid, and never greyed with the rest: it is not part
   of the decision, so the default's grey would say the wrong thing about it. */
.ca-hgate-edge { border-style: dashed; }
.ca-hgate[data-ca-hgate-editable="no"] .ca-hgate-edge { opacity: 1; filter: none; }
.ca-hgate-edge-note { font-style: italic; }

/* The day cell now carries the weekday and date as its label; same capitalisation as the
   payoff's date column, for the same reason. */
.ca-matrix-day strong { text-transform: capitalize; }

/* The venue combobox (28 Aug 2026): typing filters the catalogue, "Otro" trails the list. */
.ca-combo { position: relative; }
.ca-combo-list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 30;
  margin: 0;
  padding: 0.3rem;
  list-style: none;
  max-height: 240px;
  overflow-y: auto;
  border: 1px solid var(--ca-line);
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.14);
}
.ca-combo-list[hidden] { display: none; }
.ca-combo-opt { padding: 0.45rem 0.6rem; border-radius: 7px; font-size: 14.5px; line-height: 21px; cursor: pointer; }
.ca-combo-opt:hover { background: rgba(145, 8, 220, 0.07); }
.ca-combo-other { margin-top: 0.25rem; padding-top: 0.55rem; border-top: 1px dashed var(--ca-line); color: var(--ca-muted); font-style: italic; }

/* blank.required (P-blank-wording). One line above the per-question consequence, saying that
   this question needs an answer before the Route can be generated - decision 5, stated where
   the answer is given rather than only in the summary the customer may never open. Darker than
   .ca-none-todo because it is the rule and not the commentary, and GONE once the control is
   pressed: the requirement is news before the answer and noise after it. Keyed on the button's
   aria-pressed, the same way the Respondido chip is, so no script knows about this line. */
.ca-none-req {
  margin: 0.5rem 0 0;
  padding-left: 2.15rem;
  font-size: 14.5px;
  line-height: 22px;
  color: var(--ca-ink);
}
.ca-none-btn.ca-none-btn[aria-pressed="true"] + .ca-none-req { display: none; }

.ca-nones-note {
  margin-top: 0.9rem;
  font-size: 13.5px;
  line-height: 21px;
  color: var(--ca-muted);
}
.ca-nones-note p { margin: 0; }

/* Once the Route is built the answers are fixed, and that includes the ones that say "nothing".
   Disabled and not hidden, deliberately: what they declared is part of what the Route was built
   from, so it has to stay readable. Same argument as leaving the copy black in .ca-lockable. */
body[data-ca-state="locked"] .ca-none-btn.ca-none-btn {
  pointer-events: none;
  border-style: dashed;
  opacity: 0.75;
}
body[data-ca-state="locked"] .ca-nones-note { display: none; }

/* ------------------------------------------------- arriving from a link in the summary
   A deep link that drops somebody at the top of a long page has not helped them, so the row
   in the summary points at the CONTROL (#ca-none-*) and the script scrolls the whole section,
   using this offset to clear the site's sticky header, then marks both. The ring stays until
   they act on it rather than flashing and vanishing; the pulse is only there to catch the eye
   and is dropped entirely when the visitor has asked for less motion. */
.ca-section, .ca-none { scroll-margin-top: 96px; }

.ca-focus.ca-focus {
  border-color: var(--ca-accent);
  box-shadow: 0 0 0 3px rgba(145, 8, 220, 0.16);
}
/* The section ring alone was not enough on the page it matters most on: .ca-none has no border
   of its own, so `border-color` above did nothing and the arriving visitor got a highlighted
   SECTION with nothing marked inside it. An outline draws around the box whether or not it has
   a border, and it survives the pulse finishing - which it will have done by the time anybody
   looks at a screenshot, or at the page after a slow scroll. */
.ca-none.ca-focus {
  border-radius: 12px;
  outline: 2px solid var(--ca-accent);
  outline-offset: 3px;
  animation: ca-pulse 1.2s ease-out 2;
}
@keyframes ca-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(145, 8, 220, 0.35); }
  70%  { box-shadow: 0 0 0 10px rgba(145, 8, 220, 0); }
  100% { box-shadow: 0 0 0 0 rgba(145, 8, 220, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .ca-none.ca-focus { animation: none; }
}

/* ---------------------------------------------------------- the completeness summary
   It lives inside the shared lock modal, so it gets a wider box and a scroll: seven rows with a
   consequence each is taller than a two-sentence lock message, and a <dialog> does not scroll
   its own content by default. max-height is set on .ca-modal rather than on the summary so
   every other lock message gets the same protection at a long translation. */
.ca-modal { max-height: min(88vh, 48rem); overflow-y: auto; }
.ca-modal:has(.ca-resumen) { width: min(44rem, calc(100vw - 2rem)); }

.ca-resumen-h {
  margin: 1.4rem 0 0.6rem;
  font-family: "Poppins", Sans-serif;
  font-size: 16px;
  font-weight: 600;
  color: var(--e-global-color-8cd1398, #000);
}
.ca-resumen {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.6rem;
}
.ca-resumen li {
  margin: 0;
  padding: 0.7rem 0.9rem 0.8rem;
  border: 1px solid var(--ca-line);
  border-left: 3px solid var(--ca-accent);
  border-radius: 12px;
  background: #fbfcfd;
}
/* Doubled for the same reason every button selector in this file is doubled, and it was
   measured rather than assumed: the kit's own `a` rule won at first try and the computed
   text-decoration-line came back "none", so the rows read as headings and not as the links Pol
   asked for. They ARE the way to the thing that answers the question, so they have to look it. */
.ca-resumen-name.ca-resumen-name {
  font-size: 16px;
  font-weight: 600;
  line-height: 24px;
  color: var(--ca-ink);
  text-decoration: underline;
  text-decoration-color: rgba(145, 8, 220, 0.45);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}
.ca-resumen-name.ca-resumen-name:hover,
.ca-resumen-name.ca-resumen-name:focus-visible {
  color: var(--ca-accent);
  text-decoration-color: currentColor;
}

.ca-resumen-chip {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.05rem 0.55rem 0.1rem;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  line-height: 20px;
  white-space: nowrap;
  vertical-align: 1px;
}
.ca-resumen-chip-todo { background: rgba(21, 47, 78, 0.08); color: var(--e-global-color-65e99da, #152f4e); }
.ca-resumen-chip-none { background: var(--ca-accent); color: #fff; }

.ca-resumen-imp {
  margin: 0.35rem 0 0;
  font-size: 14.5px;
  line-height: 22px;
  color: var(--ca-muted);
}
.ca-resumen-if { font-weight: 700; color: var(--ca-ink); }

/* Which chip and which lead-in show is decided by which list the row is in, so the script never
   has to name a class - it moves the <li> and the cascade does the rest. */
#ca-resumen-todo .ca-resumen-chip-none,
#ca-resumen-todo .ca-resumen-if-done,
#ca-resumen-done .ca-resumen-chip-todo,
#ca-resumen-done .ca-resumen-if-todo { display: none; }
#ca-resumen-done li { border-left-color: #9fb0c4; background: #fff; }

.ca-resumen-none { margin-top: 1.2rem; }

/* resumen.blocked + resumen.blocked_cta (P-IX4). It sits inside [data-ca-resumen-group="todo"],
   so it is shown and hidden by the same line of script that shows and hides the pending list and
   cannot be left stranded over an empty one. Deliberately NOT red and not an alert box: decision
   5 makes this a waiting state, not an error, and every row above it can be resolved in one
   click. The rule stays quiet and the button is the loud part. */
.ca-resumen-blocked {
  margin-top: 1.1rem;
  padding: 0.9rem 1rem;
  border: 1px dashed var(--ca-line);
  border-radius: 10px;
  background: rgba(21, 47, 78, 0.03);
  font-size: 14.5px;
  line-height: 22px;
}
.ca-resumen-go-row { margin: 0.85rem 0 0; }

.ca-resumen-foot {
  margin-top: 1.4rem;
  padding-top: 1rem;
  border-top: 1px solid var(--ca-line);
  font-size: 14.5px;
  line-height: 22px;
  color: var(--ca-muted);
}

@media (max-width: 767px) {
  .ca-nones { padding: 0.9rem 0.9rem 1rem; }
  /* At 390px the chip and the label were sharing one line and the label lost, so "No vamos a
     anadir mas reservas" came out three words tall in a 120px column. flex-basis:100% on the
     label claims the rest of the line - it still shrinks to fit - which pushes the chip onto
     its own row under it. */
  .ca-none-btn.ca-none-btn { flex-wrap: wrap; font-size: 15px; line-height: 22px; }
  .ca-none-label { flex: 1 1 100%; }
  .ca-none-tag { order: 3; margin: 0.4rem 0 0 2.15rem; }
  .ca-none-todo, .ca-none-done { padding-left: 0; }
  .ca-resumen-chip { margin-left: 0; margin-top: 0.3rem; display: block; width: fit-content; }
}

/* ========================================================================================
 * THE ARTICLE PAGE
 *
 * /tu-viaje/<section>/<slug>/ - one of the 22 reading-list articles, built from
 * site/content/es/posts/ by scripts/build_site.mjs. It borrows the whole client-area chrome
 * (sub-nav, preview banner, S0, foot CTA) and adds a reading column, because the one thing a
 * reference page has to get right is the measure: .ca-prose is already sized for it, so this
 * is mostly about the head of the page and about not letting the column grow past ~70
 * characters on a wide screen.
 * ======================================================================================== */

/* The hero band's text is a <p> on an article page, so the article's own title can be the only
   <h1> - see site/templates/_ca-hero-post.html. Elementor's margin reset does not reach a <p>. */
.ca-heroline { margin: 0; }

.ca-articulo { max-width: 44rem; }
.ca-articulo-crumb {
  margin: 0 0 0.9rem;
  font-size: 14px;
  line-height: 21px;
}
.ca-articulo-crumb a, .ca-articulo-back a {
  color: var(--ca-muted);
  text-decoration: none;
  border-bottom: 1px solid var(--ca-line);
}
.ca-articulo-crumb a:hover, .ca-articulo-back a:hover {
  color: var(--ca-ink);
  border-bottom-color: currentColor;
}
.ca-articulo-h1 {
  margin: 0 0 0.6rem;
  font-family: "Poppins", Sans-serif;
  font-size: 27px;
  line-height: 35px;
  font-weight: 600;
  letter-spacing: normal;
  color: var(--e-global-color-8cd1398, #000);
}
/* The card's teaser, repeated as the page's lead. Bigger than the body and quieter than the
   title: it is there so a reader who arrived from a card can tell in one line that this is the
   article they clicked. */
.ca-articulo-lead {
  margin: 0 0 1.3rem;
  font-size: 17px;
  line-height: 27px;
  color: var(--ca-muted);
}
.ca-articulo-body p { margin: 0 0 1rem; }
.ca-articulo-body ul, .ca-articulo-body ol { margin: 0 0 1rem; }
/* CROSS-LINKS IN RUNNING TEXT, added 25 August 2026 with the de-duplication pass. Data that
   lives in another section is linked and not retyped, so a body paragraph now ends in "…está en
   Las alturas mínimas, una por una" — and that has to look like the link it is, in the middle of
   a sentence, without shouting. Accent colour and an underline that starts quiet: the same
   treatment .ca-subnav-links uses one step louder. Prose blocks on the section pages get it too,
   because the same handoff happens there (G4 → G5.4, ES → IX3). */
.ca-articulo-body a, .ca-prose a, .ca-heights-note a, .ca-tip a {
  color: var(--ca-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  text-decoration-color: rgba(145, 8, 220, 0.35);
}
.ca-articulo-body a:hover, .ca-prose a:hover,
.ca-heights-note a:hover, .ca-tip a:hover { text-decoration-color: currentColor; }
.ca-articulo-back {
  margin: 1.6rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--ca-line);
  font-size: 14px;
}

/* ---------------------------------------------------------------- the review flag
 * REVIEW SCAFFOLDING, and it is meant to be seen. An amber chip around the phrase whose park
 * fact was not confirmed when the article was written, so a reviewer reads the doubt in place
 * instead of a list at the bottom of a file nobody opens.
 *
 * It is scaffolding in exactly the way .ca-secno is, and it is guarded harder: it renders on
 * every build, so the guard is not a flag but the noindex state - scripts/build_site.mjs
 * REFUSES to write a page carrying one of these into an indexable build, and
 * tests/verificar.test.mjs fails the release if one ever gets through. Deleting the feature is
 * this rule, shared/verificar.mjs, that guard and that test.
 *
 * <mark> and not <span>: it is exactly what <mark> is for, it survives a stylesheet that never
 * loaded, and a screen reader announces it. */
.ca-verificar {
  padding: 0.05em 0.4em;
  border: 1px solid #b58105;
  border-radius: 4px;
  background: #fff4d6;
  color: #6b4a00;
  font-size: 0.82em;
  font-weight: 600;
  letter-spacing: 0.01em;
}

@media (max-width: 767px) {
  .ca-articulo-h1 { font-size: 22px; line-height: 29px; }
  .ca-articulo-lead { font-size: 16px; line-height: 25px; }
}

/* ------------------------------------------------------- a card that IS a link
 * The whole card is the <a>, not just the title: a 15rem tile with a three-word link inside it
 * is a tiny target on a phone, and the title alone is the accessible name either way. An
 * unpublished card is still an <article> with the `en preparación` chip and no link at all -
 * that rule (P-S8) is the reason both shapes exist.
 *
 * .ca-post already carries the border, the padding and the background, so this only has to undo
 * the anchor's own colour and underline and say, visibly, that it can be pressed. */
.ca-post-link {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.ca-post-link:hover, .ca-post-link:focus-visible {
  border-color: var(--ca-accent);
  box-shadow: 0 6px 18px rgba(22, 32, 46, 0.09);
  transform: translateY(-1px);
}
.ca-post-link:focus-visible { outline: 2px solid var(--ca-accent); outline-offset: 3px; }
.ca-post-link .ca-post-title { text-decoration: none; }
.ca-post-link:hover .ca-post-title { color: var(--ca-accent); }
.ca-post-go {
  display: inline-block;
  margin-top: 0.7rem;
  font-family: "DM Sans", Sans-serif;
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--ca-accent);
}
@media (prefers-reduced-motion: reduce) {
  .ca-post-link { transition: none; }
  .ca-post-link:hover, .ca-post-link:focus-visible { transform: none; }
}

/* ------------------------------------------------------------------ the return from Stripe
 *
 * #ca-pagado, opened by client-area.js when the URL carries ?paid=QL-XXXXXX. Everything here
 * exists to make ONE STRING easy to keep: the reference. It is what a customer has to quote at
 * us if the confirmation email never lands, and the failure this styling is against is somebody
 * skim-reading past it and closing the tab.
 *
 * `user-select: all` is the part worth explaining. On a phone there is no comfortable way to
 * select eight characters by dragging, and a half-selected reference is worse than none because
 * it looks like a whole one. One tap takes the lot. The copy button is the same job for people
 * who would rather press something, and it ships HIDDEN — the script unhides it only where
 * navigator.clipboard exists, because a copy button that silently does nothing is a worse
 * offer than no button.
 */
.ca-ref-box {
  margin: 0.2rem 0 1rem;
  padding: 1rem 1.1rem;
  text-align: center;
  background: var(--ca-card);
  border: 1px solid var(--ca-line);
  border-radius: 12px;
}
.ca-ref-label {
  margin: 0 0 0.35rem;
  font-family: "DM Sans", Sans-serif;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ca-muted);
}
.ca-ref {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 30px;
  line-height: 38px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--ca-ink);
  user-select: all;
  -webkit-user-select: all;
  word-break: break-all;
}
.ca-ref-copy { margin-top: 0.6rem; }
.ca-note-keep { margin-bottom: 1.1rem; }
.ca-modal-paid .ca-h4 {
  margin: 0 0 0.5rem;
  font-family: "DM Sans", Sans-serif;
  font-size: 16px;
  line-height: 23px;
  font-weight: 700;
  color: var(--ca-ink);
}
.ca-modal-paid .ca-h3 { margin-top: 0; padding-right: 2rem; }
/* The cancelled line, in the preview banner. Quiet on purpose: somebody who has just decided
   not to pay is not being sold to again, they are being reassured about one fact. */
.ca-note-cancel { margin: 0 0 0.9rem; }
@media (max-width: 480px) {
  .ca-ref { font-size: 25px; line-height: 32px; }
}

/* =============================================================== TU VIAJE, #129 (26/08/2026)
   The inverted funnel. Three groups of rules: the state machine, the planner at the top of the
   page, and the CTA block that repeats top and bottom.

   THE STATE MACHINE IS THE IMPORTANT ONE, AND WHAT IT DELIBERATELY CANNOT DO MATTERS AS MUCH
   AS WHAT IT DOES. body[data-ca-client] is `anon`, `saved` or `paid`, and every rule below
   shows or hides a LABEL, A SENTENCE OR A BUTTON. None of them touches a layout block. The
   page used to carry a segmented control that swapped whole sections in and out through
   body[data-ca-state]; #129 removed it precisely because a visitor should never find
   themselves on a different page from the one they were reading. Rebuilding that behaviour out
   of this attribute would be the same mistake wearing a new name.

   .ca-state-anon   only while nothing is saved and nothing is bought
   .ca-state-saved  only once a draft exists
   .ca-state-paid   only once the trip is paid
   .ca-state-out    anon OR saved - i.e. "there is still something to buy"
   .ca-state-in     saved OR paid  - i.e. "this device is inside a trip"

   Written as `display: none` on the non-matching states rather than `display: block` on the
   matching one, so an element keeps whatever display its own rules gave it. */
[data-ca-client="anon"]  .ca-state-saved,
[data-ca-client="anon"]  .ca-state-paid,
[data-ca-client="saved"] .ca-state-anon,
[data-ca-client="saved"] .ca-state-paid,
[data-ca-client="paid"]  .ca-state-anon,
[data-ca-client="paid"]  .ca-state-saved,
[data-ca-client="paid"]  .ca-state-out,
[data-ca-in="no"]        .ca-state-in { display: none !important; }

/* ---------------------------------------------------------------- the state line
   What the preview banner became. One sentence and at most one control; it is furniture on
   five of the six pages and must read like it. */
.ca-state {
  margin: 0 0 1.6rem;
  padding: 0.85rem 1.2rem;
  border: 1px solid var(--ca-line);
  border-left: 4px solid var(--ca-accent);
  border-radius: 12px;
  background: var(--ca-card);
  font-size: 15px;
  line-height: 24px;
}
.ca-state-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.2rem;
  align-items: baseline;
  justify-content: space-between;
}
.ca-state-say { flex: 1 1 20rem; color: var(--ca-muted); }
.ca-note-in, .ca-note-out { margin-top: 0; }

/* ---------------------------------------------------------------- the planner
   Three controls, side by side on a desktop and stacked on a phone. The email is disabled
   until the other two are answered, and a disabled control has to LOOK unavailable rather than
   merely refuse - otherwise the hint under it reads as a scold. */
.ca-viaje { border-color: var(--ca-accent); }
.ca-viaje-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem 1.4rem;
  margin: 1.2rem 0 0;
}
.ca-viaje-field { display: block; font-size: 14px; }
/* The email field is HIDDEN until date and days are set (26 Aug evening round). Stated
   explicitly because the display:block above would otherwise override the [hidden]
   attribute — the same trap [data-ca-steps] documents at the foot of this file. */
.ca-viaje-field[hidden] { display: none; }
/* The other door, in the first section's corner: compact, quiet, never competing with the
   questions themselves. */
.ca-viaje-volver { flex: 0 0 auto; }
.ca-viaje-label {
  display: block;
  margin-bottom: 0.35rem;
  font-weight: 600;
  color: var(--ca-ink);
}
.ca-viaje-field input, .ca-viaje-field select {
  width: 100%;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--ca-line);
  border-radius: 10px;
  font: inherit;
  font-size: 15px;
  background: #fff;
  color: var(--ca-ink);
}
.ca-viaje-field input:disabled {
  background: #f3f5f8;
  color: #93a1b3;
  cursor: not-allowed;
}
.ca-viaje-field [aria-invalid="true"],
.ca-viaje-field input[aria-invalid="true"],
.ca-viaje-field select[aria-invalid="true"] { border-color: var(--ca-accent); }
.ca-viaje-hint {
  display: block;
  margin-top: 0.35rem;
  font-size: 13px;
  line-height: 19px;
  color: var(--ca-muted);
}
.ca-viaje-hint [hidden] { display: none; }
.ca-viaje-save {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: center;
  margin-top: 1rem;
}
.ca-viaje-save[hidden] { display: none; }
.ca-viaje-save .ca-note { margin-top: 0; }

/* ------------------------------------------------------------- the date payoff
   What the chosen dates buy before any payment: hours, EMT, parade, closures. A quiet card -
   it is information the planner GIVES, not a step it asks for, so no accent border and no
   controls. Hidden until date and days are both set, and hidden entirely when the closures
   snapshot could not be fetched (no promises beats wrong promises). */
.ca-payoff {
  margin-top: 1.2rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  background: var(--ca-card);
}
.ca-payoff[hidden] { display: none; }
.ca-payoff-title { margin: 0 0 0.6rem; font-size: 15.5px; font-weight: 700; color: var(--ca-ink); }
.ca-payoff-subtitle { margin: 0 0 0.4rem; font-size: 14px; font-weight: 700; color: var(--ca-ink); }
.ca-payoff-days { list-style: none; margin: 0; padding: 0; }
.ca-payoff-day {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.9rem;
  padding: 0.45rem 0;
  border-top: 1px dashed var(--ca-line);
  font-size: 14px;
  line-height: 21px;
  color: var(--ca-muted);
}
.ca-payoff-day:first-child { border-top: 0; padding-top: 0; }
.ca-payoff-date {
  flex: 0 0 5.2rem;
  font-weight: 600;
  color: var(--ca-ink);
  text-transform: capitalize;
}
.ca-payoff-parade { color: var(--ca-ink); }
.ca-payoff-closures { margin-top: 0.8rem; padding-top: 0.8rem; border-top: 1px dashed var(--ca-line); }
.ca-payoff-closures[hidden] { display: none; }
.ca-payoff-closures ul { list-style: none; margin: 0; padding: 0; }
.ca-payoff-closures li { padding: 0.2rem 0; font-size: 14px; line-height: 21px; color: var(--ca-muted); }
.ca-payoff-closures strong { color: var(--ca-ink); font-weight: 600; }
.ca-payoff-nodata[hidden] { display: none; }
.ca-payoff-src { margin-top: 0.7rem; font-size: 12.5px; }

/* The tease of the payoff: the same card speaking before the dates exist. A real button,
   dressed as one thing to click - dashed where the card is solid, the CTA line underlined so
   the affordance survives a scan. Hidden the moment the payoff itself shows, and hidden like
   the card when the snapshot could not be fetched. */
.ca-payoff-tease {
  display: block;
  width: 100%;
  margin-top: 1.2rem;
  padding: 1rem 1.1rem;
  border: 1px dashed var(--ca-line);
  border-radius: 14px;
  background: transparent;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.ca-payoff-tease[hidden] { display: none; }
.ca-payoff-tease:hover,
.ca-payoff-tease:focus-visible { border-color: var(--ca-ink); background: var(--ca-card); }
.ca-payoff-tease-title { display: block; font-size: 15.5px; font-weight: 700; color: var(--ca-ink); }
.ca-payoff-tease-line { display: block; margin-top: 0.35rem; font-size: 14px; line-height: 21px; color: var(--ca-muted); }
.ca-payoff-tease-cta { display: inline-block; margin-top: 0.5rem; font-size: 13.5px; font-weight: 600; color: var(--ca-ink); text-decoration: underline; }

/* ---------------------------------------------------------------- the CTA block
   Two buttons, one visible. The price sits beside it because decision 5 of the funnel
   proposal says the control that takes money must say so and show the amount. */
.ca-go {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.4rem;
  align-items: center;
  margin: 1.6rem 0 0;
}
.ca-go-price { margin: 0; font-size: 15px; color: var(--ca-ink); }
.ca-go-price strong { font-family: "Poppins", Sans-serif; font-size: 21px; }
.ca-go-price span { display: block; font-size: 13px; color: var(--ca-muted); }
.ca-go-note { flex: 1 1 100%; margin: 0; font-size: 13px; color: var(--ca-muted); }
.ca-go-note p { margin: 0; }

/* The prompt. A statement of what is still needed, not a validation error: no red, no count,
   no icon. Same restraint the completeness summary keeps, for the same reason. */
.ca-prompt {
  margin: 1rem 0 0;
  padding: 0.85rem 1.1rem;
  border: 1px dashed var(--ca-line);
  border-radius: 12px;
  background: #fbfcfd;
  font-size: 15px;
  line-height: 23px;
}
.ca-prompt[hidden] { display: none; }
.ca-prompt-lead { margin: 0 0 0.35rem; font-weight: 600; color: var(--ca-ink); }
.ca-prompt-list { margin: 0; padding-left: 1.2rem; color: var(--ca-muted); }
.ca-prompt-list li[hidden] { display: none; }

/* ---------------------------------------------------------------- the recovery block
   Quiet, and low on the page. It is the last thing anybody needs and the only thing a
   returning customer needs, which is exactly the shape of a footer note. */
.ca-recuperar { background: #fbfcfd; }
.ca-recuperar-row { margin: 1rem 0 0; }
.ca-volver-form {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem 1rem;
  align-items: flex-end;
  margin: 1rem 0 0;
}
.ca-volver-field { flex: 1 1 12rem; font-size: 14px; }
.ca-volver-field input {
  display: block;
  width: 100%;
  margin-top: 0.3rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--ca-line);
  border-radius: 10px;
  font: inherit;
  font-size: 15px;
}
.ca-volver-alt { margin: 0.8rem 0 0; font-size: 14px; }
.ca-note-bad { color: var(--ca-ink); }
[data-ca-volver-panel][hidden] { display: none; }

/* The confirm step: what is being bought, said back, before the two ticks. */
.ca-buy-recap {
  margin: 0 0 1rem;
  padding: 0.6rem 0.8rem;
  border-radius: 10px;
  background: #f3f5f8;
  font-size: 14px;
  color: var(--ca-ink);
}
.ca-buy-recap .ca-linkish { margin-left: 0.5rem; font-size: 13px; }
.ca-buy-name { display: block; margin-bottom: 1rem; font-size: 14px; }
.ca-buy-name input {
  display: block;
  width: 100%;
  margin-top: 0.3rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--ca-line);
  border-radius: 10px;
  font: inherit;
  font-size: 15px;
}

/* The three-step ordered list, and the two section chips, are hidden rather than deleted -
   spec point 6 hides sections 1 and 3 "for now". [hidden] on a flex or grid child is ignored
   by the display property those layouts set, so it is stated once here for the wrapper. */
[data-ca-steps][hidden] { display: none !important; }

/* THE CTA BEFORE THE SAVE (26 Aug evening round): "Consigue tu itinerario" activates only
   once the answers are saved and the code has gone out by email. aria-disabled, not disabled,
   so a click still lands and the prompt can name the missing step; the dimming says "not
   yet", the prompt says why. */
.ca-cta.ca-cta[data-ca-go][aria-disabled="true"] {
  opacity: 0.55;
  box-shadow: none;
  cursor: not-allowed;
}

@media (max-width: 767px) {
  .ca-go { gap: 0.6rem 1rem; }
  .ca-go .ca-cta-go { flex: 1 1 100%; text-align: center; }
}

/* ======================================================================================
   THE RESERVATIONS BLOCK, AND ITS TWO SHAPES
   ======================================================================================
   Pol, 26 August 2026: "it should be empty but allow updating it with the new flow.
   everything is editable but only saved if they provide the email... if no dates and days
   are present then displaying a couple of fiction reservations is okey."

   The block reads two attributes and nothing else:

     [data-ca-res]        "ejemplo" (no date or no days yet) | "propio" (the grid is theirs)
     [data-ca-res-save]   "local" | "guardando" | "guardado" | "error"

   WHY THE STATE IS IN CSS AND NOT IN `hidden`. The example, its tag and its note are the
   SERVER render - they are what somebody sees with the stylesheet loaded and the script
   still parsing, and what somebody with no JavaScript sees for good. Toggling `hidden`
   from the script would paint the example note first and swap it a frame later; a rule
   keyed on an attribute the server already wrote never shows the wrong one at all. */

/* .ca-resbox replaced .ca-lockpad here. The lockpad carried data-lock on the whole grid so
   that a click anywhere in it opened "se desbloquea al comprar"; nothing in this block is
   behind the purchase any more, so it is a container and not a trap - no pointer cursor, no
   hover border, and the controls inside it are the only clickable things. */
.ca-resbox {
  position: relative;
  margin-top: 1.2rem;
  padding: 1rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  background: #fdfdff;
}

/* The hatch is the signal that this is an example and not a state, so it belongs to the
   example and goes away with it. Gradient, not an image: no request, follows the accent. */
#ca-reservations[data-ca-res="ejemplo"] .ca-resbox {
  background:
    repeating-linear-gradient(135deg, rgba(145, 8, 220, 0.045) 0 10px, transparent 10px 20px),
    #fdfdff;
}

/* .ca-example-tag draws a padlock, which was right while the example was locked and is a
   lie now that the real grid is editable by anyone. The words are kept, the glyph is not. */
#ca-reservations .ca-example-tag::before { display: none; }

/* What only makes sense while the grid is fiction. The legend explains the dashed chips and
   .ca-matrix-more says "and one row per day of your trip" - both are answers to the example,
   and in the real grid the rows ARE the days and there are no chips left to explain. */
#ca-reservations[data-ca-res="propio"] .ca-example-tag,
#ca-reservations[data-ca-res="propio"] .ca-matrix-legend,
#ca-reservations[data-ca-res="propio"] .ca-matrix-more { display: none; }

/* ------------------------------------------------------------------ the notes underneath
   One line at a time, and never two. Each is a consequence of the state above it, which is
   why they share a slot instead of stacking: a block that says "this is an example", "tap a
   gap", "this will be lost" and "saved" all at once says none of them. */
.ca-resnote {
  display: none;
  margin: 0.9rem 0 0;
  font-size: 13.5px;
  line-height: 21px;
  color: var(--ca-muted);
}
#ca-reservations[data-ca-res="ejemplo"] .ca-resnote-ejemplo,
#ca-reservations[data-ca-res="propio"][data-ca-res-save="local"] [data-ca-res-note="local"],
#ca-reservations[data-ca-res="propio"][data-ca-res-save="guardando"] [data-ca-res-note="guardando"],
#ca-reservations[data-ca-res="propio"][data-ca-res-save="guardado"] [data-ca-res-note="guardado"],
#ca-reservations[data-ca-res="propio"][data-ca-res-save="error"] [data-ca-res-note="error"] {
  display: block;
}

/* "if no email is introduced say it will be lost with a link to tu viaje email, with a small
   underlined text." Small and underlined, and no more than that: it is a consequence the
   customer is owed, not a banner selling them an account. The colour is the warning amber
   the rest of the area uses for "true and worth stopping at", not red - nothing has gone
   wrong yet, and it only will if they walk away. */
.ca-resnote-warn { color: #92400e; }
.ca-resnote-ok { color: #0f766e; }
.ca-resnote-bad { color: var(--ca-bad, #b42318); }
/* The warning is a <button> now and the example route is still an <a>; both read as the same
   small underlined text, so the button is stripped of its button-ness here rather than the
   two being styled apart. DOUBLED, per the note at the top of this file: the Elementor kit
   paints every <button> purple at (0,1,1), so the single class lost and the warning rendered
   as a solid purple bar. */
.ca-resnote-link.ca-resnote-link {
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  cursor: pointer;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.ca-resnote-link.ca-resnote-link:hover,
.ca-resnote-link.ca-resnote-link:focus-visible { text-decoration-thickness: 2px; }

/* ------------------------------------------------------------------ the real grid's cells */
/* The date beside the day number. Dimmer and lighter than "Día 2" because the ordinal is
   what the customer navigates by and the date is the confirmation. */
.ca-matrix-date {
  font-size: 13px;
  line-height: 18px;
  color: var(--ca-muted);
  font-variant-numeric: tabular-nums;
}

/* THE CELL CONTROLS DRESS THEMSELVES NOW.
   Both of them used to carry .ca-locked, and that is where they got their border, their
   background, their colour and their cursor from - the class did double duty as "this is
   behind the purchase" and "this is what a control looks like". Dropping the lock dropped the
   look with it, and they fell through to the Elementor kit's `button { background-color:
   #9108DC }`, which drew three solid purple pills where the grid wanted three empty slots.
   Measured at 390 on 26 August 2026, and it is the reason these rules exist at all. */
#ca-reservations .ca-add,
#ca-reservations .ca-cell-edit {
  border: 1px dashed var(--ca-line);
  background: transparent;
  color: var(--ca-muted);
  cursor: pointer;
}
/* Solid, because an edit control sits on something that is already there; dashed is the
   language of an empty slot and this slot is full. */
#ca-reservations .ca-cell-edit { border-style: solid; }
#ca-reservations .ca-add:hover,
#ca-reservations .ca-add:focus-visible,
#ca-reservations .ca-cell-edit:hover,
#ca-reservations .ca-cell-edit:focus-visible {
  border-color: var(--ca-accent);
  color: var(--ca-accent);
  background: rgba(145, 8, 220, 0.06);
}

/* The plus fills its cell at every width. It was a 28px circle in a 64px box because the cell
   used to be a preview with a token control in it; it is the control now, so the target is the
   cell. Nothing else in the area has a tap target that small. */
#ca-reservations .ca-matrix-cell .ca-add {
  width: 100%;
  height: auto;
  min-height: 36px;
  border-radius: 10px;
}

/* An empty cell is a control end to end, so the whole cell reacts, not just the glyph
   inside it. The dashed border it already has is the right resting state: it says "nothing
   here yet" in the same language as every other slot in the area. */
#ca-reservations[data-ca-res="propio"] .ca-matrix-cell:not(.ca-matrix-filled):hover {
  border-color: var(--ca-accent);
  background: rgba(145, 8, 220, 0.04);
}
#ca-reservations[data-ca-res="propio"] .ca-matrix-cell:has(:focus-visible) {
  border-color: var(--ca-accent);
}

/* ====================================================================== the reservation editor
   A dialog that asks the two things the clicked cell does not already fix. It reuses
   .ca-modal wholesale; only the form inside it is new. */
.ca-res-slot {
  margin: 0 0 0.6rem;
  font-family: "DM Sans", Sans-serif;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ca-accent);
}
.ca-res-form {
  display: grid;
  gap: 0.8rem;
  margin-top: 1rem;
}
/* The grid below BEATS the [hidden] attribute (author display wins over the UA rule), which
   is how the "Otro sitio" free-text box stayed on screen after a pick re-hid it - the same
   trap the modal notes near the top of this file document. Every element this class dresses
   that also toggles `hidden` needs the explicit rule. */
.ca-res-field[hidden] { display: none; }
.ca-res-field {
  display: grid;
  gap: 0.3rem;
  font-size: 14px;
  font-weight: 600;
  color: var(--ca-ink);
}
.ca-res-field input {
  width: 100%;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--ca-line);
  border-radius: 10px;
  background: #fff;
  font: inherit;
  font-weight: 400;
  color: var(--ca-ink);
}
.ca-res-field input:focus-visible {
  outline: 2px solid var(--ca-accent);
  outline-offset: 1px;
}
/* The time field is the required one and the only one that can fail, so it says so where it
   fails rather than in a summary at the bottom of the dialog. */
.ca-res-form [aria-invalid="true"] { border-color: var(--ca-bad, #b42318); }
.ca-res-inside { font-size: 14px; }
/* Shown the moment the tick comes off, which is the moment it becomes true. It used to be a
   locked button of its own - "Tengo una reserva fuera del parque" - which asked the customer
   to classify their booking before telling them why it mattered. */
.ca-res-outside[hidden], .ca-res-form .ca-note[hidden] { display: none; }
.ca-modal-res .ca-modal-actions { margin-top: 0.4rem; }

/* ==================== EXPERIMENT: the matrix transposed (Pol, 28 Aug 2026) ====================
   "try (as a test, easy to revert) placing desayuno, comida y cena as rows and days as
   columns, taking most of the width but showing enough of the next day so it is obviously
   slidable."

   Meals are rows, days are columns, and a day column takes ~80% of the width after the label
   column so the next day peeks - the peek IS the affordance. The DOM is untouched: the
   per-day .ca-matrix-row wrappers become display:contents, every child is placed into one
   transposed grid by rule, and the sticky first column is the existing .ca-matrix-head
   markup re-placed vertically. MAX_DAYS is hard-capped at 4 (shared/schema.mjs), so five
   column rules cover every trip plus the example's "more" row.

   REVERTING IS DELETING "ca-matrix-flip" FROM site/templates/tu-viaje-comida.html -
   this whole block then matches nothing and the three row layouts above take over again.
   If the experiment wins, fold it in properly and delete those instead. */
.ca-matrix.ca-matrix-flip {
  grid-template-columns: 88px;
  /* Narrower than the first cut (0.8/420) - the content is a name and an hour, and a
     narrower day shows more of the next one. */
  grid-auto-columns: min(calc((100% - 88px) * 0.7), 300px);
  /* 1fr meal rows: the three share the height of the tallest, so the rows line up whatever
     mix of filled, empty and paired cells a column holds. */
  grid-template-rows: auto repeat(3, 1fr);
  gap: 0.5rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-bottom: 0.4rem;
}
.ca-matrix-flip .ca-matrix-head,
.ca-matrix-flip .ca-matrix-row { display: contents; }

/* The meal names, from horizontal header to sticky row-label column. */
.ca-matrix-flip .ca-matrix-head span {
  grid-column: 1;
  position: sticky;
  left: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  padding: 0 0.3rem 0 0;
  background: #fdfdff;          /* .ca-resbox ground: the labels must cover sliding cells */
  font-size: 13px;
  font-weight: 600;
  color: var(--ca-muted);
}
.ca-matrix-flip .ca-matrix-head span:nth-child(1) { grid-row: 1; }
.ca-matrix-flip .ca-matrix-head span:nth-child(2) { grid-row: 2; }
.ca-matrix-flip .ca-matrix-head span:nth-child(3) { grid-row: 3; }
.ca-matrix-flip .ca-matrix-head span:nth-child(4) { grid-row: 4; }

/* Each day-row's children share one column; which one is the row's position. Child 1 of the
   matrix is the head, so the days start at 2. */
.ca-matrix-flip > :nth-child(2) > * { grid-column: 2; }
.ca-matrix-flip > :nth-child(3) > * { grid-column: 3; }
.ca-matrix-flip > :nth-child(4) > * { grid-column: 4; }
.ca-matrix-flip > :nth-child(5) > * { grid-column: 5; }
.ca-matrix-flip > :nth-child(6) > * { grid-column: 6; }

/* And inside a day: label on top, then the three meals, in markup order. */
.ca-matrix-flip .ca-matrix-row > :nth-child(1) { grid-row: 1; }
.ca-matrix-flip .ca-matrix-row > :nth-child(2) { grid-row: 2; }
.ca-matrix-flip .ca-matrix-row > :nth-child(3) { grid-row: 3; }
.ca-matrix-flip .ca-matrix-row > :nth-child(4) { grid-row: 4; }

/* The day label is a column header now - horizontal at every width (the 767px layout turns
   it on its side, and these out-specific it), and the snap target for the slide. */
.ca-matrix-flip .ca-matrix-day {
  writing-mode: horizontal-tb;
  transform: none;
  display: flex;
  flex-direction: row;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.2rem 0.2rem 0.1rem;
  font-size: 14.5px;
  line-height: 1.3;
  scroll-snap-align: start;
  scroll-margin-left: calc(88px + 0.5rem);
}

/* One cell look at every width: the base card, re-asserted over both phone layouts. */
.ca-matrix-flip .ca-matrix-cell {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  justify-content: center;
  min-height: 64px;
  padding: 0.5rem;
  border: 1px dashed var(--ca-line);
  border-radius: 12px;
  background: #fbfcfd;
}
.ca-matrix-flip .ca-matrix-cell.ca-matrix-filled { padding: 9px 10px; }
.ca-matrix-flip .ca-matrix-meal { display: none; }
.ca-matrix-flip .ca-add.ca-add { width: 100%; }

/* The example's "y una fila por cada día" note becomes the peeking ghost column, spanning
   the meal rows - which is exactly what it describes. */
.ca-matrix-flip .ca-matrix-more .ca-matrix-day {
  grid-row: 1 / 5;
  align-items: center;
  justify-content: center;
  text-align: left;
  padding: 0.4rem;
  font-size: 13.5px;
  color: var(--ca-muted);
}
/* The pencil is gone: the first instinct on a filled cell is to click the cell, and the
   editor it opens already offers change and delete. The button stays in the markup as a
   full-cell invisible overlay, so the keyboard still tabs to it, the screen reader still
   hears "Cambiar Cena jue, 24 sep", and the delegated handler still finds
   [data-ca-res-edit]. */
/* ID-prefixed on purpose: #ca-reservations .ca-add / .ca-cell-edit set the borders with
   (1,1,0) specificity, and a class-only override silently loses to them - which is exactly
   how the "removed" dashed rectangle survived its first removal. */
#ca-reservations .ca-matrix-flip .ca-matrix-cell .ca-cell-edit {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 12px;
  background: transparent;
  cursor: pointer;
}
.ca-matrix-flip .ca-matrix-cell .ca-cell-edit .ca-i { display: none; }
.ca-matrix-flip .ca-matrix-cell .ca-cell-edit:focus-visible {
  outline: 2px solid var(--ca-accent);
  outline-offset: 1px;
}
.ca-matrix-flip .ca-matrix-filled:hover { border-color: var(--ca-accent); }
.ca-matrix-flip .ca-cell-what { padding-right: 0; }

/* The plus needs no dotted rectangle of its own: the empty cell already is one. The button
   fills the cell invisibly, same treatment as the pencil overlay. */
#ca-reservations .ca-matrix-flip .ca-add.ca-add {
  width: 100%;
  height: 100%;
  min-height: 0;
  border: 0;
  background: transparent;
}

/* ================================================== end of the transposed-matrix experiment */

/* ============================================== the party editor on /grupo/ (#159, 29 Aug 2026)
   Hand-maintained, like the rest of this file: no build regenerates it, and a block that
   arrives here without rules renders as bare markup on a page nobody looks at logged out.
   That has happened once already, which is why tests/party-editor.test.mjs asks whether this
   stylesheet has heard of `ca-party` at all.

   THE STATE MACHINE IS TWO ATTRIBUTES ON THE SECTION, exactly the reservations grid's:

     [data-ca-party]        "ejemplo" | "propio"
     [data-ca-party-save]   "idle" | "local" | "guardando" | "guardado" | "error"

   In CSS and not in `hidden`, for the reason the grid gives: the example IS the server render,
   so a rule keyed on an attribute the server already wrote never shows the wrong one, while
   toggling `hidden` from the script would paint one and swap it a frame later. */
.ca-partybox {
  position: relative;
  margin-top: 1.2rem;
  padding: 1rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  background: #fdfdff;
}

/* The hatch says "this is an example, not a state", so it belongs to the example and leaves
   with it. Gradient rather than an image: no request, and it follows the accent token. */
#ca-party[data-ca-party="ejemplo"] .ca-partybox {
  background:
    repeating-linear-gradient(135deg, rgba(145, 8, 220, 0.045) 0 10px, transparent 10px 20px),
    #fdfdff;
}

/* .ca-example-tag draws a padlock. That was right while the block was a locked preview and is
   a lie now that anyone can fill it in - same removal as /comida/. */
#ca-party .ca-example-tag::before { display: none; }

/* THE EXAMPLE IS HIDDEN, NEVER DESTROYED. It is markup, the script only ever adds and removes
   [data-ca-party-person] rows, and this is the rule that takes the fiction away. So removing
   the last person brings the shape back rather than leaving an empty box - the one thing the
   preview was written to explain is what a party looks like. */
#ca-party[data-ca-party="propio"] .ca-party-example { display: none; }

/* ---------------------------------------------------------------------- a person's row */
.ca-party-row .ca-people-who {
  flex-direction: row;
  align-items: center;
  gap: 0.45rem;
}
.ca-party-sel {
  width: 100%;
  padding: 0.34rem 0.4rem;
  border: 1px solid var(--ca-line);
  border-radius: 9px;
  background: #fff;
  font: inherit;
  font-size: 14.5px;
  line-height: 21px;
  color: var(--ca-ink);
}
.ca-party-sel:focus-visible { outline: 2px solid var(--ca-accent); outline-offset: 1px; }
.ca-party-sel:disabled { color: var(--ca-muted); background: #f4f6f9; }

/* A finished row loses the dashed "nothing here yet" language of its cells, so the ones still
   waiting for an answer are the ones that look like they are. */
#ca-party [data-ca-party-done="yes"] .ca-people-cell { border-style: solid; }

/* Doubled, per the note at the top of this file: the Elementor kit paints every <button>
   purple at (0,1,1), so a single class loses and this would render as a solid pill. */
.ca-party-x.ca-party-x {
  flex: none;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--ca-line);
  border-radius: 50%;
  background: transparent;
  color: var(--ca-muted);
  font: inherit;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}
.ca-party-x.ca-party-x:hover,
.ca-party-x.ca-party-x:focus-visible { border-color: var(--ca-bad); color: var(--ca-bad); }

/* THE SUGGESTION HAS TO LOOK LIKE AN OFFER AND NOT LIKE AN ANSWER. It is a dashed pill under
   the height select, in the accent voice, and the select above it is still on its placeholder
   while it shows. A suggestion pre-selected inside the select would be the pre-ticked height
   band from the hosted form wearing a different hat. */
.ca-party-suggest.ca-party-suggest {
  align-self: stretch;
  padding: 0.2rem 0.55rem;
  border: 1px dashed var(--ca-accent);
  border-radius: 999px;
  background: transparent;
  color: var(--ca-accent);
  font: inherit;
  font-size: 12.5px;
  line-height: 18px;
  text-align: left;
  cursor: pointer;
}
.ca-party-suggest[hidden] { display: none; }
.ca-party-suggest.ca-party-suggest:hover,
.ca-party-suggest.ca-party-suggest:focus-visible { background: rgba(145, 8, 220, 0.06); }

/* ------------------------------------------------------------------------ adding people */
.ca-party-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  margin: 0.8rem 0 0;
}
.ca-party-add.ca-party-add {
  width: auto;
  border: 1px dashed var(--ca-line);
  background: transparent;
  color: var(--ca-muted);
  cursor: pointer;
}
.ca-party-add.ca-party-add:hover,
.ca-party-add.ca-party-add:focus-visible {
  border-color: var(--ca-accent);
  color: var(--ca-accent);
  background: rgba(145, 8, 220, 0.06);
}
.ca-party-add[hidden] { display: none; }
.ca-party-full { font-size: 13.5px; color: var(--ca-muted); }
.ca-party-full[hidden] { display: none; }

/* ------------------------------------------------------------------ the note underneath
   One line at a time and never two, sharing .ca-resnote's slot and colours with the grid.
   "idle" matches nothing on purpose: with an address and nothing saved yet there is no news,
   and claiming "guardado" for a row nobody has written would be a statement about the past
   this page cannot check. */
#ca-party[data-ca-party-save="local"] [data-ca-party-note="local"],
#ca-party[data-ca-party-save="guardando"] [data-ca-party-note="guardando"],
#ca-party[data-ca-party-save="guardado"] [data-ca-party-note="guardado"],
#ca-party[data-ca-party-save="error"] [data-ca-party-note="error"] {
  display: block;
}

/* ------------------------------------------------------------------------ declared blank
   FROZEN, NOT DELETED. "Preferimos no detallar el grupo" greys the rows and takes their
   controls; every row is still there and pressing it again gives them back. The script holds
   the keyboard half (the selects are disabled), because pointer-events alone leaves a
   perfectly usable dropdown behind for anyone with a keyboard. */
#ca-party[data-ca-party-frozen] .ca-people { opacity: 0.55; filter: grayscale(1); }
#ca-party[data-ca-party-frozen] .ca-party-sel,
#ca-party[data-ca-party-frozen] .ca-party-x,
#ca-party[data-ca-party-frozen] .ca-party-suggest { pointer-events: none; }

/* --------------------------------------------------------------- the rows on a phone
   MEASURED AT 390, 29 August 2026: .ca overflowed to 408px and the height select was squeezed
   to its arrow with the suggestion pill running off the right edge. The shared narrow-width
   rule above turns a .ca-people-cell into a label-and-value ROW, and a <select> at width:100%
   beside a label is wider than the card by construction.

   Three declarations fix it and none of them is a width: the cell may wrap, the select takes
   whatever is left (min-width:0, because a flex item will not shrink below its content
   otherwise - the specific reason the cell overflowed rather than the select getting small),
   and the suggestion takes a line of its own instead of being a third thing competing for the
   same one. It has the longest text on the row; competing was never going to work. */
@media (max-width: 767px) {
  /* The pad narrows too, exactly as .ca-lockpad and .ca-resbox do at this width and for the
     same measured reason: at 1rem the row cards inside it pushed .ca to a scrollWidth of 344
     against a width of 332. /alojamiento/, which draws the same rows inside a lockpad, reports
     332 == 332, which is what said the padding was the difference and not the rows. */
  .ca-partybox { padding: 0.8rem 8px; }
  #ca-party .ca-people-cell { flex-wrap: wrap; column-gap: 0.6rem; row-gap: 0.4rem; }
  #ca-party .ca-people-lbl { flex: none; }
  #ca-party .ca-party-sel { width: auto; flex: 1 1 auto; min-width: 0; }
  #ca-party .ca-party-suggest { flex: 1 0 100%; }
}

/* THE ADD BUTTON IS DELIBERATELY NOT GREYED. It is the positive answer to the question the
   declaration answers negatively, so pressing it releases the declaration - the same pairing
   as "sí, tenemos" and "nadie del grupo" on /comida/. Greying it out would leave a frozen
   block whose only way out is the control that froze it. */

/* The withdrawal line at the generate button (Pol, 4 September 2026). Quieter than the note
   above it - it is a legal statement rather than an instruction - but not hidden, because a
   waiver the customer did not read at the moment of the click does not carry. */
.ca-go-legal {
  margin: 0.35rem 0 0;
  font-size: 13px;
  line-height: 19px;
  color: var(--ca-muted);
}

/* ---------------------------------------------------------------- sign in with Google (#247)
 *
 * Two blocks share these: the persistent door inside the "ya tengo un viaje" dialog and the
 * save-your-progress prompt on the planner. Both ship `hidden`, so none of this is on screen
 * until the script has a client id AND Google's button has actually rendered.
 *
 * The BUTTON itself is Google's own rendered element and is deliberately not styled here beyond
 * centring it - their branding guidelines own its colour, padding, font and logo, and a rule of
 * ours reaching inside it is how a compliant button stops being one. */
.ca-google {
  margin: 1rem 0 0;
}

.ca-google-prompt {
  padding: 1rem 1.1rem 1.15rem;
  border: 1px solid var(--ca-line);
  border-radius: 14px;
  /* Distinct from the page but quieter than the purchase CTA it sits above: this is an offer,
     and the thing below it is the decision. */
  background: var(--ca-tint, #f7f7f9);
}

.ca-google-title {
  margin: 0 0 0.35rem;
  font-weight: 600;
}

.ca-google-button {
  display: flex;
  justify-content: center;
  margin: 0.75rem 0 0.5rem;
  /* Google renders an iframe whose width it controls; this keeps it from stretching oddly in
     the dialog, which is narrower than the planner. */
  min-height: 44px;
}

.ca-google-failed {
  margin: 0.5rem 0 0;
  color: var(--ca-warn, #8a3b12);
}

.ca-google-saved {
  margin: 0.5rem 0 0;
}

/* The separator in the dialog, between the one-tap door and the code + email form. A line with
   the word centred on it, which is the conventional shape and needs no extra markup. */
.ca-google-or {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1rem 0 0.25rem;
  color: var(--ca-muted);
  font-size: 13px;
}

.ca-google-or::before,
.ca-google-or::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--ca-line);
}

/* SCROLL LOCK WHILE A DIALOG IS OPEN (Pol, 4 September 2026: "with the payment modal opened,
   there should be no scroll on the background").

   position:fixed rather than overflow:hidden, because overflow:hidden on the body does NOT hold
   on iOS Safari - the page scrolls behind the dialog anyway and then lands somewhere else when it
   closes. The cost of position:fixed is that the body loses its scroll offset, so client-area.js
   stashes it, writes it here as a negative `top`, and scrolls back to it on release. The class is
   added and removed by the observer in that file, which derives it from whether any <dialog> is
   open - so no close path can leave it stuck. */
body.ca-scroll-locked {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overflow: hidden;
  /* `top` is set inline to the stashed offset, so the page does not jump to its start. */
}

/* The detail-page footer lost its paragraph (Pol, 4 September 2026: remove the explainer). The
   aside is display:flex with justify-content:space-between, which was right for text-then-button
   and leaves a lone button pinned to the left of a wide bordered box. Centred when it is the only
   child, so the removal changes what is said without leaving a layout that looks unfinished.
   Nothing changes on any page that still has both. */
.ca-foot > .ca-cta:only-child { margin-inline: auto; }
