/* ---------------------------------------------------------------------------
   samael.online - availability + travels
   ATRSP S267009, window B (site side)

   NEW FILE. Loaded from an absolute path so page depth cannot break it:
       <link rel="stylesheet" href="/css/availability.css?v=...">

   It never redefines anything in style.css. Every selector is prefixed .av-
   so it cannot collide with the existing sheet. All colours come from the
   live design tokens declared in style.css :root
       --black #0a0a0a  --black-card #111  --black-hover #1a1a1a
       --red #8b1a1a    --red-bright #c41e3a
       --gold #c8a45a   --gold-dim #a88a3a  --gold-bright #e0c06a
       --white #f5f0eb  --text #d4cfc8      --text-muted #8a8580
       --border #222    --radius 4px        --transition .3s ease

   ===========================================================================
   FOUR DAY STATES (schema 1.1), plus one render-only state
   ---------------------------------------------------------------------------
     available      green   open time, the only state that carries slots
     fully_booked   RED     rostered, nothing left. SCARCITY, not absence.
     on_request     gold    Wed-Sat with no shift, arrangeable
     unavailable    grey    absence. Recessive on purpose.
     unknown        dashed  RENDER ONLY. Never in the JSON.

   fully_booked is CAUSE-BLIND. A day consumed by guest bookings and a day
   consumed by a private commitment are the same value, the same bytes and the
   same pixels. Never add a variant, a modifier or a tooltip that could tell
   them apart, and never hint at a cause.

   unknown is ALL OR NOTHING at the document level. Either every cell in the
   grid is .av-unk or none is. It is produced only by the dead-document path in
   availability.js, which has no access to per-day data. The moment one day can
   render unknown while its neighbours render real states, unknown becomes a
   per-day signal and starts leaking again. availability.js asserts this after
   every paint.
   ===========================================================================  */

/* --- local aliases, so a state colour is defined exactly once -------------- */
.av-scope{
  --av-open-fg:#7fce9f;   --av-open-bd:#2f5f42;  --av-open-bg:rgba(47,95,66,.18);
  --av-full-fg:#e0808c;   --av-full-bd:#6b2029;  --av-full-bg:rgba(196,30,58,.15);
  --av-req-fg:#e0c06a;    --av-req-bd:#5c4a20;   --av-req-bg:rgba(92,74,32,.22);
  --av-off-fg:#9a8f8f;    --av-off-bd:#3a3030;   --av-off-bg:rgba(58,48,48,.30);
  --av-unk-fg:#8a8580;    --av-unk-bd:#2f2c28;
}

/* --- shared bits ---------------------------------------------------------- */
.av-pill{
  display:inline-flex; align-items:center; gap:.35rem;
  font-size:.68rem; font-weight:600; letter-spacing:.06em; text-transform:uppercase;
  padding:.2rem .6rem; border-radius:999px; border:1px solid; white-space:nowrap;
  font-family:'Inter','Segoe UI',system-ui,sans-serif; line-height:1.6;
}
.av-pill.av-open{ color:var(--av-open-fg); border-color:var(--av-open-bd); background:var(--av-open-bg) }
.av-pill.av-full{ color:var(--av-full-fg); border-color:var(--av-full-bd); background:var(--av-full-bg) }
.av-pill.av-req { color:var(--av-req-fg);  border-color:var(--av-req-bd);  background:var(--av-req-bg)  }
.av-pill.av-off { color:var(--av-off-fg);  border-color:var(--av-off-bd);  background:var(--av-off-bg)  }

.av-sr{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

.av-note{ font-size:.85rem; color:var(--text-muted); margin:.75rem 0 0 }
.av-note a{ color:var(--gold) }

/* --- legend --------------------------------------------------------------- */
.av-legend{
  display:flex; gap:1.4rem; flex-wrap:wrap; align-items:center;
  padding:1rem 0 1.6rem; font-size:.82rem; color:var(--text-muted);
}
.av-legend-item{ display:inline-flex; align-items:center; gap:.5rem }
.av-key{ width:11px; height:11px; border-radius:2px; border:1px solid; flex:none }
.av-key.av-open{ background:var(--av-open-bg); border-color:var(--av-open-bd) }
.av-key.av-full{ background:var(--av-full-bg); border-color:var(--av-full-bd) }
.av-key.av-req { background:var(--av-req-bg);  border-color:var(--av-req-bd)  }
.av-key.av-off { background:var(--av-off-bg);  border-color:var(--av-off-bd)  }

/* --- month calendar ------------------------------------------------------- */
.av-months{ display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:2.5rem }
.av-month-name{
  font-family:'Playfair Display',Georgia,serif; color:var(--white);
  font-size:1.15rem; font-weight:700; margin:0 0 .8rem; letter-spacing:.02em;
}
.av-weekdays,.av-grid{ display:grid; grid-template-columns:repeat(7,1fr); gap:4px }
.av-weekdays{
  margin-bottom:4px; font-size:.66rem; letter-spacing:.14em; text-transform:uppercase;
  color:var(--text-muted); text-align:center;
}
.av-weekdays span{ padding:.25rem 0 }

.av-day{
  aspect-ratio:1/1; display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:.15rem; border:1px solid var(--border);
  border-radius:var(--radius); background:var(--black-card);
  font-size:.9rem; font-variant-numeric:tabular-nums; color:var(--text-muted);
  min-height:44px;
}
.av-day.av-pad{ border-color:transparent; background:transparent }
.av-day.av-open{ background:var(--av-open-bg); border-color:var(--av-open-bd); color:var(--white); font-weight:600 }
.av-day.av-full{ background:var(--av-full-bg); border-color:var(--av-full-bd); color:var(--white); font-weight:600 }
.av-day.av-req { background:var(--av-req-bg);  border-color:var(--av-req-bd);  color:var(--white) }
/* NO opacity here, and none below. Recession is a COLOUR decision, made once in
   the token block at the top; opacity is a legibility tax charged on top of it.
   .av-off is on screen on every published trip by design and .av-unk is on
   screen for EVERY cell whenever the document is dead, which is the exact
   moment a guest most needs to read the page. Measured on the real page
   background: .av-off 3.85:1 -> 5.77:1, .av-unk 2.62:1 -> 5.42:1, against a
   4.5:1 AA floor. The recessive reading survives intact, because it never came
   from the dimming: these two are the only states with no white numeral, no
   bold weight and no saturated fill. */
.av-day.av-off { background:var(--av-off-bg);  border-color:var(--av-off-bd);  color:var(--av-off-fg) }
/* Render-only. Dashed and empty reads as "no data", never as "blocked". */
.av-day.av-unk { background:transparent; border-style:dashed; border-color:var(--av-unk-bd); color:var(--av-unk-fg) }
.av-day-n{ line-height:1 }
.av-day-mark{ font-size:.58rem; line-height:1.2; letter-spacing:.06em; text-transform:uppercase }
.av-day.av-open .av-day-mark{ color:var(--av-open-fg) }
.av-day.av-full .av-day-mark{ color:var(--av-full-fg) }

/* --- dead-document notice. Shown only when EVERY day is unknown. ---------- */
.av-deadnotice{
  border:1px solid var(--gold-dim); border-left:3px solid var(--gold);
  border-radius:0 var(--radius) var(--radius) 0;
  background:var(--black-card); padding:1.2rem 1.4rem; margin-bottom:1.6rem;
  display:flex; flex-direction:column; gap:.6rem;
}
.av-deadnotice h3{ margin:0; color:var(--gold); font-size:1.05rem }
.av-deadnotice p{ margin:0; color:var(--text-muted); font-size:.9rem }
.av-deadnotice .btn{ align-self:flex-start; margin-top:.2rem }

/* --- scarcity line under the open list ------------------------------------ */
.av-booked{
  font-size:.86rem; color:var(--text-muted); margin-top:1.1rem;
  padding-top:1rem; border-top:1px solid var(--border);
}
.av-booked b{ color:var(--av-full-fg); font-weight:600 }

/* --- open-times list ------------------------------------------------------ */
.av-open-list{ display:flex; flex-direction:column; gap:.5rem; margin-top:.5rem }
.av-row{
  display:grid; grid-template-columns:170px 1fr auto; gap:1rem; align-items:center;
  background:var(--black-card); border:1px solid var(--border);
  border-radius:var(--radius); padding:.75rem 1rem;
  transition:border-color var(--transition);
}
.av-row:hover{ border-color:var(--gold-dim) }
.av-row-day{ font-size:.78rem; color:var(--text-muted); text-transform:uppercase; letter-spacing:.1em }
.av-row-times{ display:flex; flex-wrap:wrap; gap:.45rem }
.av-time{
  font-size:.95rem; color:var(--white); font-variant-numeric:tabular-nums;
  letter-spacing:.02em; background:var(--black-hover); border:1px solid var(--border);
  border-radius:var(--radius); padding:.15rem .55rem; white-space:nowrap;
}
.av-row .btn{ padding:.4rem 1rem; font-size:.72rem; white-space:nowrap }

.av-empty{
  border:1px dashed var(--border); border-radius:var(--radius);
  padding:1.6rem 1.4rem; color:var(--text-muted); font-size:.92rem;
}

/* --- tour hub ------------------------------------------------------------- */
.av-tour{ display:flex; flex-direction:column }
.av-tour-row{
  display:grid; grid-template-columns:132px 1fr auto 14px; gap:1rem; align-items:center;
  padding:1rem .3rem; border-top:1px solid var(--border);
  transition:background var(--transition);
}
.av-tour-row:last-child{ border-bottom:1px solid var(--border) }
a.av-tour-row{ color:inherit }
a.av-tour-row:hover{ background:var(--black-card) }
.av-tour-date{
  font-size:.75rem; letter-spacing:.13em; text-transform:uppercase; color:var(--gold);
  font-variant-numeric:tabular-nums; font-weight:600;
}
.av-tour-city{
  font-family:'Playfair Display',Georgia,serif; font-size:1.35rem; color:var(--white);
  letter-spacing:.02em; line-height:1.25;
}
.av-tour-city small{
  display:block; font-family:'Inter','Segoe UI',system-ui,sans-serif; font-size:.75rem;
  color:var(--text-muted); letter-spacing:0; margin-top:.15rem;
}
.av-chev{ color:var(--text-muted); font-size:1rem; text-align:right }
/* A sold-out trip recedes by CHANGING COLOUR, not by fading. Gold is the
   colour of a date you can still have, so a sold-out date gives it up and drops
   to muted; the city name steps down from --white to --text. The old
   opacity:.55 took the date to 3.21:1 and the country line under it to 2.38:1,
   on a row that is still a link to a page a guest may well want. Measured now:
   date 5.42:1, city 12.78:1, country line 5.42:1. */
.av-tour-row.av-dim .av-tour-date{ color:var(--text-muted) }
.av-tour-row.av-dim .av-tour-city{ color:var(--text) }

/* --- city chips (past visits / on request) -------------------------------- */
.av-chips{ display:flex; flex-wrap:wrap; gap:.6rem; margin-top:.3rem }
.av-chip{
  display:inline-flex; align-items:baseline; gap:.5rem;
  border:1px solid var(--border); border-radius:var(--radius);
  padding:.55rem .95rem; background:var(--black-card); font-size:.9rem; color:var(--text);
  transition:border-color var(--transition);
}
a.av-chip:hover{ border-color:var(--gold-dim); color:var(--text) }
.av-chip b{ font-family:'Playfair Display',Georgia,serif; color:var(--white); font-weight:700 }
.av-chip i{ font-style:normal; font-size:.76rem; color:var(--text-muted) }

/* --- city page slots ------------------------------------------------------ */
.av-slots{ display:flex; flex-direction:column; gap:.5rem }
.av-slot{
  display:grid; grid-template-columns:150px 1fr auto; gap:1rem; align-items:center;
  background:var(--black-card); border:1px solid var(--border);
  border-radius:var(--radius); padding:.7rem 1rem;
}
.av-slot .av-row-day{ white-space:nowrap }
/* A day inside the trip window with no hours left. Same tokens as the Berlin
   grid's fully_booked cell, and no opacity: dimming this row was measured at
   3.21:1 and is the reason the token set exists. */
.av-slot-gone{ background:var(--av-full-bg); border-color:var(--av-full-bd) }
.av-time-gone{ color:var(--av-full-fg); background:transparent; border-color:var(--av-full-bd) }
.av-tz{ font-size:.78rem; color:var(--text-muted); margin-top:.7rem; letter-spacing:.02em }

/* --- travel special ------------------------------------------------------- */
.av-special{
  border:1px solid #4a3c1e; border-radius:var(--radius);
  background:linear-gradient(160deg,rgba(200,164,90,.09),rgba(200,164,90,.02));
  padding:1.6rem 1.7rem; display:flex; flex-direction:column; gap:.7rem;
}
.av-special h3{ color:var(--gold-bright); margin:0 }
.av-special-price{
  font-family:'Playfair Display',Georgia,serif; color:var(--red-bright);
  font-size:1.5rem; font-variant-numeric:tabular-nums;
}
.av-special-min{
  font-size:.74rem; color:var(--text-muted); text-transform:uppercase;
  letter-spacing:.14em; margin-left:.6rem;
}
.av-special p{ font-size:.9rem; color:var(--text); margin:0 }
.av-special .btn{ align-self:flex-start; margin-top:.3rem }

/* --- sold-out reordering --------------------------------------------------
   When a city sells out the page REORDERS rather than empties: the travel
   special moves above the dates and leads with "make your own". Hiding it on a
   sold-out city loses exactly the guest who is most motivated.

   Done with flex `order` rather than by moving nodes, so the source order
   stays sensible for a crawler and for a screen reader that ignores order,
   and so availability.js can flip it at runtime when a city sells out between
   two builds. availability.js sets data-av-soldout on the container.          */
[data-av-cityblocks]{ display:flex; flex-direction:column; gap:3rem }
[data-av-cityblocks] .av-block-dates  { order:2 }
[data-av-cityblocks] .av-block-special{ order:3 }
[data-av-cityblocks][data-av-soldout="1"] .av-block-special{ order:1 }

/* --- offerings ------------------------------------------------------------ */
.av-offers{ display:flex; flex-direction:column; border-top:1px solid var(--border) }
.av-offer{
  display:grid; grid-template-columns:1fr auto; gap:1rem; align-items:baseline;
  padding:.9rem .2rem; border-bottom:1px solid var(--border);
}
.av-offer-name{ color:var(--gold); font-weight:600; font-size:.95rem }
.av-offer-desc{
  display:block; color:var(--text-muted); font-size:.85rem; font-weight:400;
  margin-top:.2rem; max-width:56ch;
}
.av-offer-link{ font-size:.75rem; color:var(--text); white-space:nowrap }

/* --- channels ------------------------------------------------------------- */
.av-channels{ display:flex; gap:.5rem; flex-wrap:wrap; margin-top:1rem; align-items:center }
.av-chan{
  display:inline-flex; align-items:center; gap:.35rem; font-size:.78rem;
  border:1px solid var(--border); border-radius:999px; padding:.35rem .9rem; color:var(--text);
  transition:border-color var(--transition);
}
.av-chan.av-wa{ border-color:#1f5c36; color:#5fcf8b }
.av-chan.av-tg{ border-color:#1f4a5c; color:#5fb2cf }
.av-chan.av-em{ border-color:#4a4030; color:var(--gold) }
.av-chan:hover{ filter:brightness(1.2) }

/* --- "not on the list" invite module -------------------------------------- */
.av-invite{
  border:1px dashed #4a3c1e; border-radius:var(--radius); padding:1.6rem 1.7rem;
  display:flex; flex-direction:column; gap:.8rem; background:rgba(200,164,90,.04);
}
.av-invite h3{ margin:0 }

/* --- compact strip (high-intent pages) ------------------------------------ */
.av-strip{
  border-top:1px solid var(--border); border-bottom:1px solid var(--border);
  padding:1.1rem 0; margin:2rem 0; display:flex; align-items:center;
  gap:1rem 1.4rem; flex-wrap:wrap;
}
.av-strip-label{
  font-size:.68rem; text-transform:uppercase; letter-spacing:.22em;
  color:var(--red-bright); font-weight:600; flex:none;
}
.av-strip-days{ display:flex; gap:.9rem; flex-wrap:wrap; align-items:center; flex:1 }
.av-strip-day{ font-size:.88rem; color:var(--text) }
.av-strip-day b{ font-family:'Playfair Display',Georgia,serif; color:var(--white); font-weight:700 }
.av-strip-day i{ font-style:normal; color:var(--gold); font-variant-numeric:tabular-nums }
.av-strip-sep{ color:#3a342c }
.av-strip .btn{ padding:.4rem 1rem; font-size:.72rem }

/* --- staging banner. Never present in a live build; verify.py refuses it. -- */
.av-staging{
  background:#3a2410; border:1px solid var(--gold-dim); color:var(--gold-bright);
  padding:.7rem 1rem; border-radius:var(--radius); font-size:.82rem;
  margin-bottom:1.5rem; text-align:center; letter-spacing:.02em;
}

/* --- responsive ----------------------------------------------------------- */
@media (max-width:820px){
  .av-months{ grid-template-columns:1fr; gap:2rem }
  .av-tour-row{ grid-template-columns:104px 1fr auto; row-gap:.5rem }
  .av-chev{ display:none }
  .av-tour-city{ font-size:1.15rem }
  .av-row,.av-slot{ grid-template-columns:1fr; row-gap:.5rem; justify-items:start }
  .av-row .btn,.av-slot .btn{ width:100% ; text-align:center }
  .av-offer{ grid-template-columns:1fr; row-gap:.35rem }
  .av-strip{ flex-direction:column; align-items:flex-start }
}
@media (max-width:420px){
  /* min-height is a FLOOR on a 1fr column, so it sets the grid's min-content
     width: 7 x 38px + 6 x 4px gap = 290px inside a 256px container at 320px,
     which scrolled the whole page sideways by 2px on its own, independently of
     the tour row below. 7 x 32 + 24 = 248 fits. It does not shrink anything in
     practice: the columns are 1fr, so at 320px they resolve to 33.1px and the
     floor never binds. Day cells are not tap targets, so the 44px touch
     minimum does not apply to them. */
  .av-day{ min-height:32px; font-size:.8rem }
  /* The mark is the ONLY non-colour difference between an open day and a sold
     out one: a slot count against the fixed cause-blind glyph. It used to be
     display:none here, which is 320-412px, i.e. most of the phone market, and
     left colour alone carrying the distinction. It is shrunk, never hidden.
     Measured in Edge at 320px: the cell resolves to 33x33 with a 31px content
     box, the numeral takes 12.8 and the mark 10, so both fit. */
  .av-day-mark{ font-size:.52rem; letter-spacing:.04em }

  /* .av-tour-row's 104px date column plus a nowrap booking pill needs 324px of
     a 256px content box, so the pill was pushed 36px past the right edge of the
     viewport and the page scrolled sideways. The date gets its own line and the
     fixed column goes away entirely. */
  .av-tour-row{ grid-template-columns:1fr auto; column-gap:.6rem; row-gap:.3rem }
  .av-tour-date{ grid-column:1 / -1 }
}
@media (prefers-reduced-motion:reduce){
  .av-row,.av-chip,.av-chan,.av-tour-row{ transition:none }
}

/* ===========================================================================
   THE HERO.

   Eight 1600x900 renders existed from 9 August and were referenced by zero
   pages. This is the band that finally shows them.

   EVERY SELECTOR HERE IS `.av-hero*` ON PURPOSE. The live style.css - which is
   always present, because the chrome is copied from the live site - defines
   `.hero`, `.hero-bg` and `.hero-content` as the home page's rotating
   slideshow: `min-height:100vh`, `position:absolute;inset:0`, and
   `filter:brightness(.35)` on the image. Borrow any one of those three names
   and every travels page gets a full-viewport dark panel where a 16:9 band
   belongs. The namespace is the whole defence.
   =========================================================================== */
.av-hero{
  position:relative;
  width:100%;
  aspect-ratio:16 / 9;
  max-height:62vh;
  overflow:hidden;
  display:flex;
  align-items:flex-end;
  margin-bottom:1rem;
  background:#0a0a0a;          /* the ground while the image decodes */
}
.av-hero-img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  object-position:50% 42%;
  /* Deliberately NOT the .35 the home page uses. That value is tuned for
     white uppercase display type at 4.5rem over a full viewport; here the
     type sits in the lower left of a much shorter band and .55 keeps the
     render legible as a photograph rather than a texture. */
  filter:brightness(.55);
  z-index:0;
}
/* The veil is a gradient, not a flat wash: it darkens only where the text
   actually sits, so the right two thirds of the render stay visible. */
.av-hero-veil{
  position:absolute; inset:0; z-index:1;
  background:linear-gradient(
    100deg,
    rgba(10,10,10,.92) 0%,
    rgba(10,10,10,.78) 28%,
    rgba(10,10,10,.35) 55%,
    rgba(10,10,10,.55) 100%
  );
}
.av-hero-inner{
  position:relative; z-index:2;
  width:100%;
  max-width:var(--max-w, 1140px);
  margin:0 auto;
  padding:0 2rem 2.4rem;
}
/* The overline is the live-updating date. availability.js rewrites the text of
   [data-av-cityrange] on every load, so this may go from empty to a date after
   first paint; reserving its line stops the h1 jumping when it does. */
.av-hero .overline{
  display:block;
  min-height:1.1em;
  margin-bottom:.35rem;
}
.av-hero h1{
  margin:0 0 .6rem;
  max-width:16ch;
  text-shadow:0 2px 24px rgba(0,0,0,.75);
}
.av-hero-intro{
  color:var(--text, #d4cfc8);
  max-width:46ch;
  margin:0;
  font-size:.98rem;
  line-height:1.7;
  text-shadow:0 1px 12px rgba(0,0,0,.8);
}

/* Tall-and-narrow phones: 16:9 leaves too little height for three lines of
   type over the image, so the band grows and the copy takes the full width. */
@media (max-width:640px){
  .av-hero{ aspect-ratio:4 / 3; max-height:none }
  .av-hero-inner{ padding:0 1.2rem 1.6rem }
  .av-hero h1{ max-width:none }
  .av-hero-intro{ max-width:none; font-size:.92rem }
}

/* ===========================================================================
   PICKABLE DAYS.

   A day a guest can ask about is a control; a day he cannot is not. Only
   `available` and `on_request` cells get this class, so only they carry a
   cursor, a hover state or a focus ring.

   That asymmetry is deliberate and it is the same cause-blind rule the colours
   already follow: a fully booked day and a day he simply is not working must
   stay indistinguishable, and an affordance is a tell. Open and on-request are
   already visually distinct from both, so giving THEM an affordance reveals
   nothing that the legend does not.
   =========================================================================== */
.av-day-pick{
  cursor:pointer;
  transition:transform .12s ease, filter .12s ease, box-shadow .12s ease;
}
.av-day-pick:hover{
  filter:brightness(1.35);
  transform:translateY(-1px);
}
.av-day-pick:focus-visible{
  outline:2px solid var(--gold, #c8a45a);
  outline-offset:2px;
  filter:brightness(1.35);
}
/* Older engines that do not know :focus-visible still need a visible ring,
   or a keyboard user is moving through the grid blind. */
.av-day-pick:focus{
  outline:2px solid var(--gold, #c8a45a);
  outline-offset:2px;
}
.av-day-pick:active{ transform:translateY(0) }

/* The confirmation line. Rendered empty and filled only when a day is picked,
   so a screen reader hears what happened instead of the page silently
   scrolling somewhere. */
.av-picked{
  min-height:1.4em;
  margin:.6rem 0 0;
  font-size:.85rem;
  color:var(--gold, #c8a45a);
}

@media (prefers-reduced-motion:reduce){
  .av-day-pick{ transition:none }
  .av-day-pick:hover{ transform:none }
}
