/* ═══════════════════════════════════════════════════════════════
   PÄÄSKYLÄNRINNE 6 — guest portal
   Shares the site's token system (see css/main.css).
   ═══════════════════════════════════════════════════════════════ */

:root{
  --ink:      #17150f;
  --ink-2:    #211e15;
  --bone:     #f1ead9;
  --bone-2:   #e7ddc4;
  --amber:    #c68a3f;
  --amber-2:  #e2ab55;
  --petrol:   #33655c;
  --petrol-d: #223f38;
  --clay:     #9c5b41;

  --font-display: 'Cardinal', 'Instrument Serif', Georgia, serif;
  --font-body: 'Plus Jakarta Sans', 'Neue Haas Grotesk', system-ui, sans-serif;
  --font-mono: 'FH Alpha', 'Plus Jakarta Sans', system-ui, sans-serif;
  --r: 4px;
}

*,*::before,*::after{ box-sizing:border-box; margin:0; padding:0; }
[hidden]{ display:none !important; }
body{
  font-family:var(--font-body); color:var(--ink); background:var(--bone);
  line-height:1.6; -webkit-font-smoothing:antialiased; min-height:100svh;
}
/* the same generated paper ground the light sections of the site use, so the
   portal reads as the same place rather than a separate admin tool.
   The column layout pins the footer: panes vary a lot in height (Wallet can be
   two lines, Add-ons is fourteen cards) and in normal flow the footer simply
   followed the content, jumping up the screen on the short ones. */
.app{
  display:flex; flex-direction:column; min-height:100svh;
  position:relative;
  background:
    linear-gradient(rgba(240,234,224,.93), rgba(240,234,224,.93)),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Cfilter id='q'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.012' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='600' height='600' filter='url(%23q)' opacity='0.5'/%3E%3Crect width='600' height='600' filter='url(%23p)' opacity='0.22'/%3E%3C/svg%3E") top center / 600px auto repeat;
}
img{ max-width:100%; display:block; }
a{ color:var(--petrol); }
button{ font:inherit; cursor:pointer; }
:focus-visible{ outline:2px solid var(--amber); outline-offset:3px; }

h1,h2,h3{ font-family:var(--font-display); font-weight:400; line-height:1.1; }
h2{ font-size:clamp(1.7rem,4vw,2.4rem); }
.mono{ font-family:var(--font-mono); font-weight:500; font-size:.78rem; letter-spacing:.08em;
  font-variant-numeric:tabular-nums; }
.eyebrow{ color:var(--clay); font-size:.82rem; margin-bottom:.6rem; }
.eyebrow span{ opacity:.55; }

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.5rem;
  font-family:var(--font-mono); font-size:.8rem; letter-spacing:.06em;
  padding:.8rem 1.5rem; border-radius:var(--r); text-decoration:none;
  border:1px solid transparent; transition:all .22s;
}
.btn--solid{ background:var(--amber); color:var(--ink); border-color:var(--amber); }
.btn--solid:hover{ background:var(--amber-2); }
.btn--line{ border-color:rgba(23,21,15,.28); color:var(--ink); background:transparent; padding:.5rem 1rem; }
.btn--line:hover{ background:var(--ink); color:var(--bone); }
.btn[disabled]{ opacity:.5; cursor:default; }

/* ── forms ─────────────────────────────────────────────── */
.form{ display:flex; flex-direction:column; gap:1rem; }
.form[hidden]{ display:none; }
.form__row{ display:grid; grid-template-columns:1fr 1fr; gap:1rem; }
.form label{ display:flex; flex-direction:column; gap:.35rem;
  font-family:var(--font-mono); font-size:.7rem; letter-spacing:.08em; text-transform:uppercase; }
.form input,.form select,.form textarea{
  font-family:var(--font-body); font-size:.95rem; color:var(--ink);
  padding:.75rem .85rem; border:1px solid rgba(23,21,15,.22); border-radius:var(--r);
  background:#f7f2e6;
}
.form input:focus,.form textarea:focus{ outline:none; border-color:var(--petrol); }
.form .btn{ align-self:flex-start; }

/* ── login ─────────────────────────────────────────────── */
.login{
  min-height:100svh; display:flex; align-items:center; justify-content:center;
  padding:1.5rem; position:relative; overflow:hidden;
}
/* warm ink over the twilight frame, the same scrim the village section uses —
   it darkens for legibility without tinting the photograph */
.login::before{
  content:""; position:absolute; inset:0; z-index:0;
  background:
    linear-gradient(rgba(23,21,15,.58) 0%, rgba(23,21,15,.48) 40%, rgba(23,21,15,.88) 100%),
    url('../assets/living-hero-1600.webp') center/cover;
}
/* The original framed the sign-in with a pair of Balinese penjor poles. There
   is no equivalent ornament here and inventing one would be decoration for its
   own sake, so the photograph carries the panel by itself. */
.login__card{
  position:relative; z-index:1;
  width:min(430px,100%); border-radius:8px;
  padding:clamp(1.8rem,5vw,2.6rem);
  background:rgba(241,234,217,.94);
  backdrop-filter:blur(10px) saturate(1.1);
  -webkit-backdrop-filter:blur(10px) saturate(1.1);
  box-shadow:0 40px 90px -34px rgba(12,11,8,.85);
  text-align:center;
}
/* height:auto is load-bearing: the width/height attributes map to CSS
   presentation hints, so without it height=555 stretches the mark vertically */
.login__markwrap{ position:relative; display:inline-block; line-height:0; margin:0 auto .2rem; }
.login__mark{ display:none; }
/* The card is a near-opaque bone panel, so the wordmark has to be ink. It was
   bone on bone: legible only as a faint ghost, and invisible entirely against
   the lighter part of the photograph behind it. */
.login__wordmark{
  display:block; font-family:var(--font-display);
  font-size:clamp(1.5rem, 5.5vw, 2.3rem); line-height:1.05;
  color:var(--ink); letter-spacing:-.01em; margin-bottom:.3rem;
}
.login__wordmark em{ font-style:italic; color:var(--clay); }
.login__markUNUSED{ display:block; width:min(210px,66%); height:auto; margin:0 auto;
  filter:invert(1); opacity:.88; }
.login__one{
  position:absolute; right:-4%; bottom:-4%;
  width:clamp(2.4rem,11vw,3.4rem); height:auto;
  pointer-events:none;
}
.login__rule{ width:150px; height:auto; margin:.8rem auto 1.2rem; opacity:.45; }
.login .eyebrow{ letter-spacing:.24em; text-transform:uppercase; font-size:.68rem; }
.login h1{ margin-bottom:.5rem; }
.login__sub{ opacity:.8; font-size:.95rem; margin-bottom:1.4rem; }
.login .form{ text-align:left; }
.login .form .btn{ align-self:stretch; }
.login__err{ color:var(--clay); }
.login__help{ margin-top:1.4rem; opacity:.75; }

/* ── app frame ─────────────────────────────────────────── */
.app__top{
  display:flex; align-items:center; gap:1.2rem; flex-wrap:wrap;
  padding:1rem clamp(1.2rem,4vw,2.5rem);
  background:var(--ink); color:var(--bone);
}
/* matches .nav__brand on the marketing page exactly, so the header reads as
   the same masthead rather than a second identity */
.app__brand{
  font-family:var(--font-display); letter-spacing:.24em; font-size:1.05rem;
  color:var(--bone); text-decoration:none; display:inline-flex; align-items:center;
}
.app__stay{ opacity:.7; margin-right:auto; }
.app__top .btn--line{ border-color:rgba(241,234,217,.3); color:var(--bone); }
.app__top .btn--line:hover{ background:var(--bone); color:var(--ink); }

.app__tabs{
  display:flex; gap:.3rem; overflow-x:auto; scrollbar-width:none;
  padding:.6rem clamp(1.2rem,4vw,2.5rem);
  background:var(--ink); border-bottom:1px solid rgba(241,234,217,.12);
  position:sticky; top:0; z-index:10;
}
.app__tabs::-webkit-scrollbar{ display:none; }
.app__tabs button{
  background:none; border:0; color:var(--bone); opacity:.6; white-space:nowrap;
  padding:.55rem .9rem; border-radius:99px; font-size:.74rem; letter-spacing:.07em;
  text-transform:uppercase; transition:opacity .2s, background .2s;
}
.app__tabs button:hover{ opacity:1; }
.app__tabs button.is-active{ opacity:1; background:rgba(226,171,85,.16); color:var(--amber-2); }
.app__badge{
  display:inline-block; min-width:1.15rem; text-align:center; padding:.05rem .3rem;
  background:var(--amber); color:var(--ink); border-radius:99px; margin-left:.25rem;
}

.app__main{ flex:1 0 auto; width:100%; max-width:1080px; margin-inline:auto; padding:clamp(1.6rem,4vw,3rem) clamp(1.2rem,4vw,2.5rem) 4rem; }
.pane h2{ margin-bottom:.5rem; }
/* The one deliberate exception: running prose keeps a reading measure.
   Everything structural fills the column, so every pane shares a right edge. */
.pane__lead{ opacity:.8; max-width:var(--measure); margin-bottom:1.8rem; }
.pane__subhead{ letter-spacing:.18em; text-transform:uppercase; color:var(--clay); margin:2.2rem 0 1rem; }

.app__foot{
  margin-top:auto;
  display:flex; justify-content:space-between; gap:1rem; flex-wrap:wrap;
  padding:1.2rem clamp(1.2rem,4vw,2.5rem);
  background:var(--ink); color:var(--bone); opacity:.9;
}
.app__foot a{ color:var(--amber-2); }

/* ── overview ──────────────────────────────────────────── */
.ov-grid{ display:grid; grid-template-columns:repeat(2,1fr); gap:1.1rem; }
.ov-card{
  border:1px solid rgba(23,21,15,.15); border-radius:var(--r);
  padding:1.5rem; background:#f6f1e4;
}
.ov-card h3{ font-family:var(--font-mono); font-size:.72rem; letter-spacing:.18em;
  text-transform:uppercase; color:var(--clay); margin-bottom:.7rem; }
.ov-card__big{ font-family:var(--font-display); font-size:1.35rem; }
.ov-card__dim{ opacity:.65; margin-top:.5rem; line-height:1.8; }
.ov-card--accent{ background:linear-gradient(130deg, rgba(51,101,92,.1), rgba(198,138,63,.12));
  display:flex; flex-direction:column; gap:.6rem; align-items:flex-start; }
.ov-card--accent .btn{ margin-top:auto; }

/* ── guide ─────────────────────────────────────────────── */
.guide{ display:flex; flex-direction:column; gap:.6rem; }
.guide details{
  border:1px solid rgba(23,21,15,.15); border-radius:var(--r); background:#f6f1e4;
}
.guide summary{
  cursor:pointer; padding:1rem 1.3rem; font-family:var(--font-display); font-size:1.1rem;
  list-style:none; display:flex; justify-content:space-between; align-items:center;
}
.guide summary::after{ content:"+"; font-family:var(--font-mono); color:var(--clay); }
.guide details[open] summary::after{ content:"−"; }
/* The indent used to live on the paragraphs themselves, which meant every
   child that was not a <p> — the entry-code list, the wifi block, the photo
   grids — sat hard against the left edge while the prose beside it was inset.
   It belongs to the container's children, so anything added later lines up
   without having to be told to. */
.guide details > *:not(summary){ padding-inline:1.3rem; }
.guide details > *:not(summary):last-child{ padding-bottom:1.2rem; }
.guide details p{ margin:0 0 .9rem; opacity:.85; font-size:.95rem; }
.guide details p:last-child{ margin-bottom:0; }
/* Nested paragraphs (inside #guideEntry and #guideWifi) are already inset by
   their wrapper, so they must not be inset twice. */
.guide details > *:not(summary) p{ padding-inline:0; }

/* ── add-ons ───────────────────────────────────────────── */
.feat{ display:grid; grid-template-columns:repeat(2,1fr); gap:1.1rem; }
.feat .svc{ background:linear-gradient(130deg, rgba(51,101,92,.09), rgba(198,138,63,.1)); }
.svc-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:1rem; }
.svc{
  border:1px solid rgba(23,21,15,.15); border-radius:var(--r);
  padding:1.3rem; background:#f6f1e4; display:flex; flex-direction:column; gap:.45rem;
}
.svc h4{ font-family:var(--font-display); font-weight:400; font-size:1.15rem; }
.svc p{ font-size:.88rem; opacity:.8; flex-grow:1; }
.svc footer{ display:flex; justify-content:space-between; align-items:center; gap:.6rem; margin-top:.5rem; }
.svc footer .mono{ color:var(--clay); font-size:.7rem; }

/* ── wallet ────────────────────────────────────────────── */
.wallet{ display:flex; flex-direction:column; gap:.6rem; }
.wallet__empty{ opacity:.7; }
.worder{
  display:grid; grid-template-columns:1fr auto auto; gap:.4rem 1.2rem; align-items:center;
  border:1px solid rgba(23,21,15,.15); border-radius:var(--r); background:#f6f1e4;
  padding:1rem 1.2rem;
}
.worder__name{ font-weight:600; }
.worder__meta{ grid-column:1; font-size:.78rem; opacity:.65; }
.worder__price{ font-family:var(--font-mono); font-size:.85rem; white-space:nowrap; }
.worder__status{
  font-family:var(--font-mono); font-size:.66rem; letter-spacing:.1em; text-transform:uppercase;
  padding:.3rem .7rem; border-radius:99px; white-space:nowrap;
}
.worder__status--requested{ background:rgba(198,138,63,.18); color:#7a5322; }
.worder__status--confirmed{ background:rgba(51,101,92,.16); color:var(--petrol-d); }
.worder__status--done{ background:rgba(23,21,15,.1); }
.worder__status--cancelled{ background:rgba(23,21,15,.06); opacity:.6; text-decoration:line-through; }
.worder__cancel{ background:none; border:0; font-family:var(--font-mono); font-size:.7rem;
  color:var(--clay); text-decoration:underline; grid-column:3; justify-self:end; }
.wallet__total{
  margin-top:1.2rem; padding:1.1rem 1.3rem;
  border:1px dashed rgba(23,21,15,.3); border-radius:var(--r);
  display:flex; justify-content:space-between; font-size:.9rem;
}

/* ── what's on ─────────────────────────────────────────── */
.evlist{ list-style:none; }
.evlist li{
  display:grid; grid-template-columns:130px 1fr; gap:1.2rem;
  padding:1.1rem 0; border-bottom:1px solid rgba(23,21,15,.14);
}
.evlist li:first-child{ border-top:1px solid rgba(23,21,15,.14); }
.ev__when{ color:var(--petrol); text-transform:uppercase; letter-spacing:.08em; padding-top:.2rem; }
.ev__tag{
  display:inline-block; font-family:var(--font-mono); font-size:.62rem; letter-spacing:.12em;
  text-transform:uppercase; padding:.15rem .55rem; border-radius:99px; margin-left:.5rem;
  vertical-align:middle; background:rgba(51,101,92,.14); color:var(--petrol-d);
}
.ev__tag--ceremony{ background:rgba(156,91,65,.16); color:#6d3a26; }
.ev__tag--season{ background:rgba(198,138,63,.18); color:#7a5322; }
.evlist h4{ display:inline; }
.evlist p{ font-size:.92rem; opacity:.8; margin-top:.25rem; }
.evlist a{ font-size:.82rem; }

/* ── photos ────────────────────────────────────────────── */
.drop{
  display:flex; flex-direction:column; align-items:center; gap:.6rem; text-align:center;
  border:2px dashed rgba(23,21,15,.25); border-radius:6px; padding:2.2rem 1.5rem;
  cursor:pointer; transition:border-color .2s, background .2s;
}
.drop:hover{ border-color:var(--amber); background:rgba(198,138,63,.05); }
.drop__icon{ font-size:1.6rem; color:var(--clay); }
.drop i{ font-style:normal; opacity:.6; }
.drop__status{ margin-top:.8rem; color:var(--petrol); }
.shots{ display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:.8rem; margin-top:1.5rem; }
.shots figure{ position:relative; border-radius:var(--r); overflow:hidden; aspect-ratio:1; background:#e4dcc6; }
.shots img{ width:100%; height:100%; object-fit:cover; }
.shots button{
  position:absolute; top:.4rem; right:.4rem; width:26px; height:26px; border-radius:50%;
  border:0; background:rgba(23,21,15,.65); color:var(--bone); line-height:1;
}

/* ── after ─────────────────────────────────────────────── */

.rebook{
  border:1px dashed var(--petrol); border-radius:6px; padding:1.8rem;
  background:rgba(51,101,92,.06); margin-bottom:1.5rem;
}
.rebook__code{
  font-family:var(--font-mono); font-size:1.5rem; letter-spacing:.14em; color:var(--petrol-d);
  padding:.4rem 0; user-select:all;
}
.after__links{ display:flex; gap:.8rem; flex-wrap:wrap; margin-top:1rem; }
.after p{ opacity:.85; margin-bottom:.8rem; }

/* ── modal ─────────────────────────────────────────────── */
.modal{ position:fixed; inset:0; z-index:60; display:flex; align-items:center; justify-content:center; padding:1rem; }
.modal[hidden]{ display:none; }
.modal__scrim{ position:absolute; inset:0; background:rgba(23,21,15,.7); backdrop-filter:blur(3px); }
.modal__card{ position:relative; width:min(440px,100%); background:var(--bone); border-radius:6px; padding:2rem; }
.modal__card h3{ margin-bottom:.2rem; }
.modal__price{ color:var(--clay); margin-bottom:1.2rem; }
.modal__x{ position:absolute; top:.7rem; right:.9rem; background:none; border:0; font-size:1.5rem; opacity:.6; }

/* ── toast ─────────────────────────────────────────────── */
.toast{
  position:fixed; bottom:1.4rem; left:50%; transform:translateX(-50%) translateY(20px);
  background:var(--ink); color:var(--bone); font-family:var(--font-mono); font-size:.8rem;
  padding:.8rem 1.4rem; border-radius:99px; opacity:0; pointer-events:none;
  transition:opacity .3s, transform .3s; z-index:70; max-width:90vw; text-align:center;
}
.toast.is-on{ opacity:1; transform:translateX(-50%) translateY(0); }


/* ═══ design layer ═══════════════════════════════════════════
   Everything below exists to make the portal feel like the rest
   of the site rather than a dashboard bolted to the side of it. */

/* a welcome band: the guest's name over villa photography, the same
   move the marketing hero makes, at a quieter scale */
.welcome{
  position:relative; overflow:hidden; border-radius:8px;
  margin-bottom:clamp(1.6rem,4vw,2.4rem);
  min-height:clamp(190px,26vw,280px);
  display:flex; flex-direction:column; justify-content:flex-end;
  padding:clamp(1.4rem,4vw,2.2rem);
  color:var(--bone);
  background:
    linear-gradient(rgba(23,21,15,.15) 0%, rgba(23,21,15,.55) 55%, rgba(23,21,15,.88) 100%),
    url('../assets/mezzanine-tv-1600.webp') center 55% / cover;
}
.welcome h2{ color:var(--bone); font-size:clamp(1.9rem,5vw,3rem); margin-bottom:.35rem; }
.welcome .pane__lead{ color:var(--bone); opacity:.88; margin-bottom:0; max-width:36rem; }
.welcome__rule{ width:150px; opacity:.5; margin-bottom:.9rem; }

/* section headings carry the divider ornament, as on the marketing page */
.pane__subhead{ display:flex; align-items:center; gap:.9rem; }
.pane__subhead::after{
  content:""; flex:1; height:1px; background:rgba(23,21,15,.18);
}

/* add-ons become picture cards rather than text boxes */
.svc{ padding:0; overflow:hidden; }
.svc__img{
  aspect-ratio:16/10; background:#e4dcc6; overflow:hidden;
}
.svc__img img{
  width:100%; height:100%; object-fit:cover;
  transition:transform .5s cubic-bezier(.2,.6,.2,1);
}
.svc:hover .svc__img img{ transform:scale(1.05); }
.svc__body{ padding:1.15rem 1.2rem 1.25rem; display:flex; flex-direction:column; gap:.4rem; flex:1; }
.feat .svc__img{ aspect-ratio:16/9; }

/* the offering, as on the team section, closing the stay */
/* the container widens so the offering gets its own column; the copy stays at
   a readable measure rather than running under the artwork */
.after{ position:relative; }
.after > *:not(.after__offering){ max-width:44rem; }
.after__offering{
  position:absolute; top:0; right:0; width:clamp(96px,13vw,160px);
  opacity:.92; pointer-events:none;
  filter:drop-shadow(0 18px 28px rgba(23,21,15,.22));
}
.rebook{ position:relative; z-index:1; }

/* arrival guide: a photograph to anchor it, matching the site's feature blocks */
.guide-hero{
  border-radius:8px; overflow:hidden; margin-bottom:1.6rem;
  aspect-ratio:21/9; background:#e4dcc6;
}
.guide-hero img{ width:100%; height:100%; object-fit:cover; }

/* photo drop zone on the paper ground */
.drop{ background:rgba(247,242,230,.7); }

@media (max-width: 640px){
  .after__offering{ display:none; }
  .login::after{ background-size:auto 60%, auto 48%; opacity:.2; }
  .welcome{ min-height:170px; }
}

/* ── responsive ────────────────────────────────────────── */
@media (max-width: 860px){
  .svc-grid{ grid-template-columns:1fr 1fr; }
}
@media (max-width: 640px){
  .ov-grid{ grid-template-columns:1fr; }
  .feat{ grid-template-columns:1fr; }
  .svc-grid{ grid-template-columns:1fr; }
  .form__row{ grid-template-columns:1fr; }
  .evlist li{ grid-template-columns:1fr; gap:.3rem; }
  .worder{ grid-template-columns:1fr auto; }
  .worder__cancel{ grid-column:2; }
}

@media (prefers-reduced-motion: reduce){
  *{ transition-duration:.01ms !important; }
}


/* ═══════════════ guest details ═══════════════
   Added 2026-07-30. The form the villa team would otherwise chase over
   the message thread: flights, who is coming, food, requests. What the guest saves here shows
   on Your stay and pre-fills the add-ons that depend on it. */

:root{ --measure:44rem; }

.detform{
  background:var(--panel, rgba(247,242,230,.7));
  border:1px solid var(--line, rgba(35,31,22,.14));
  border-radius:12px; padding:clamp(1.1rem,2.4vw,1.6rem);
  margin-bottom:2rem; display:flex; flex-direction:column; gap:1.4rem;
}
.detform__head h3{ margin:0 0 .3rem; font-size:1.15rem; }
.detform__head p{ margin:0; opacity:.75; font-size:.9rem; max-width:var(--measure); }

.detform__set{ border:0; padding:0; margin:0; display:flex; flex-direction:column; gap:.75rem; }
.detform__set + .detform__set{ border-top:1px solid var(--line, rgba(35,31,22,.12)); padding-top:1.2rem; }
.detform__set legend{
  font-family:var(--font-mono, inherit); font-size:.68rem; letter-spacing:.16em;
  text-transform:uppercase; opacity:.62; padding:0; margin-bottom:.2rem;
}

/* auto-fit rather than fixed columns: the fields reflow on their own and the
   grid never leaves a lone orphan on its own row at tablet widths */
.detform__grid{ display:grid; gap:.75rem 1rem; grid-template-columns:repeat(auto-fit,minmax(11rem,1fr)); }
.detform__grid--two{ grid-template-columns:repeat(auto-fit,minmax(16rem,1fr)); }

.detform label{ display:flex; flex-direction:column; gap:.32rem; font-size:.86rem; }
.detform label small{ opacity:.6; font-size:.78rem; }
.detform input[type=text],.detform input[type=date],.detform input[type=time],
.detform input[type=number],.detform input[type=tel],.detform select,.detform textarea{
  font:inherit; font-size:.95rem; color:inherit;
  background:var(--field, #fffdf6);
  border:1px solid var(--field-line, rgba(35,31,22,.22));
  border-radius:8px; padding:.6rem .7rem; width:100%;
  min-height:44px;                     /* comfortable touch target on a phone */
  transition:border-color .18s, box-shadow .18s;
}
.detform textarea{ min-height:auto; resize:vertical; line-height:1.5; }
.detform :is(input,select,textarea):focus-visible{
  outline:none; border-color:var(--amber, #b9812f);
  box-shadow:0 0 0 3px rgba(185,129,47,.18);
}
/* The box itself stays visually small, but the whole row is the tap target,
   so it clears the 44px minimum on a phone. */
/* `.detform label` is (0,1,1) and would otherwise beat a lone `.detform__check`
   class, stacking the box above its text and centring it. Matched on the
   element too so the row wins. */
.detform label.detform__check{
  flex-direction:row; align-items:center; justify-content:flex-start;
  gap:.65rem; font-size:.9rem; cursor:pointer; min-height:44px; padding:.2rem 0;
}
.detform label.detform__check input{
  width:1.15rem; height:1.15rem; flex:none; margin:0; accent-color:var(--amber,#b9812f);
}
.detform label.detform__check span{ flex:1 1 auto; }

.detform__foot{ display:flex; align-items:center; gap:1rem; flex-wrap:wrap; }
.detform__status{ font-size:.86rem; opacity:.75; }
.detform__status.is-ok{ color:var(--profit, #2f6357); opacity:1; }
.detform__status.is-err{ color:var(--clay, #9c5b41); opacity:1; }
.detform__divider{ margin:0 0 .9rem; opacity:.62; font-size:.68rem; letter-spacing:.16em; text-transform:uppercase; }

/* summary of those details, on Your stay */
.ov-card--wide{ grid-column:1 / -1; }
.ov-card__head{ display:flex; align-items:baseline; justify-content:space-between; gap:1rem; margin-bottom:.6rem; }
.ov-card__head h3{ margin:0; }
.btn--sm{ padding:.35rem .75rem; font-size:.76rem; }

.factlist{ margin:0; display:grid; gap:.55rem 1.5rem; grid-template-columns:repeat(auto-fit,minmax(15rem,1fr)); }
.factlist__row{ display:flex; flex-direction:column; gap:.12rem; min-width:0; }
.factlist dt{
  font-family:var(--font-mono, inherit); font-size:.64rem; letter-spacing:.14em;
  text-transform:uppercase; opacity:.58;
}
.factlist dd{ margin:0; font-size:.95rem; overflow-wrap:anywhere; }

.ov-card--prompt{ background:var(--panel-2, rgba(240,233,215,.8)); }
.ov-card--prompt p{ margin:0 0 .9rem; max-width:var(--measure); }

/* why a service came pre-filled */
.modal__prefill{
  margin:-.3rem 0 .9rem; font-size:.84rem; color:var(--profit, #2f6357);
  display:flex; align-items:center; gap:.4rem;
}
.modal__prefill::before{ content:"\2713"; font-size:.9em; }

@media (max-width:560px){
  .detform__grid,.detform__grid--two{ grid-template-columns:1fr; }
  .ov-card__head{ flex-direction:column; align-items:flex-start; gap:.5rem; }
}


/* wallet totals, read from the folio */
.wtot__row{ display:flex; justify-content:space-between; align-items:baseline; gap:1rem; padding:.25rem 0; }
.wtot__row--dim{ opacity:.7; font-size:.92rem; }
.wtot__row--due{ border-top:1px solid var(--line, rgba(35,31,22,.14)); margin-top:.4rem; padding-top:.6rem; }
.wtot__row--due strong{ color:var(--profit, #2f6357); }
.wtot__note{ margin:.7rem 0 0; font-size:.83rem; opacity:.66; }


/* ═══════════════ status, timeline, issues, paying ═══════════════
   Added 2026-07-30. Status is encoded in shape and colour as well as the word,
   so the state of a stay reads at a glance rather than needing to be parsed. */

.chip{
  display:inline-flex; align-items:center; gap:.3rem; white-space:nowrap;
  font-family:var(--font-mono, inherit); font-size:.62rem; letter-spacing:.1em;
  text-transform:uppercase; padding:.22rem .5rem; border-radius:99px;
  border:1px solid currentColor; line-height:1.4;
}
.chip::before{ content:""; width:5px; height:5px; border-radius:50%; background:currentColor; }
.chip--requested{ color:var(--muted, #726a58); }
.chip--confirmed{ color:var(--amber, #b9812f); }
.chip--scheduled{ color:var(--amber, #b9812f); }
.chip--done,.chip--fixed{ color:var(--profit, #2f6357); }
.chip--cancelled{ color:var(--faint, #9a9078); }
.chip--reported{ color:var(--muted, #726a58); }
.chip--seen{ color:var(--amber, #b9812f); }
.chip--in_hand{ color:var(--clay, #9c5b41); }

/* ── the stay, in order ── */
.tline{ list-style:none; margin:0; padding:0; position:relative; }
.tline::before{
  content:""; position:absolute; left:6px; top:.6rem; bottom:.6rem;
  width:1px; background:var(--line-strong, rgba(35,31,22,.2));
}
.tline__item{
  position:relative; padding:.5rem 0 .5rem 1.75rem;
  display:flex; flex-wrap:wrap; align-items:baseline; gap:.3rem .6rem;
}
.tline__item::before{
  content:""; position:absolute; left:2px; top:.95rem;
  width:9px; height:9px; border-radius:50%;
  background:var(--bg, #efe8d8); border:1.5px solid var(--line-strong, rgba(35,31,22,.35));
}
.tline__item--key::before{ background:var(--amber, #b9812f); border-color:var(--amber, #b9812f); }
.tline__item.is-past{ opacity:.55; }
.tline__when{
  font-family:var(--font-mono, inherit); font-size:.66rem; letter-spacing:.1em;
  text-transform:uppercase; opacity:.62; flex:0 0 auto; min-width:9.5rem;
}
.tline__title{ font-weight:600; }
.tline__meta{ opacity:.7; font-size:.88rem; flex-basis:100%; padding-left:9.5rem; }

/* ── reported issues ── */
.issues{ display:flex; flex-direction:column; gap:.6rem; margin-bottom:2rem; }
.issues__head{ margin:0 0 .2rem; font-size:.68rem; letter-spacing:.16em; text-transform:uppercase; opacity:.62; }
.issue{
  background:var(--panel, rgba(247,242,230,.7));
  border:1px solid var(--line, rgba(35,31,22,.14));
  border-radius:10px; padding:.85rem 1rem; display:flex; flex-direction:column; gap:.3rem;
}
.issue__top{ display:flex; align-items:center; justify-content:space-between; gap:1rem; }
.issue__detail{ margin:0; font-size:.9rem; opacity:.8; }
.issue__note{
  margin:.15rem 0 0; font-size:.9rem; padding:.5rem .7rem; border-radius:8px;
  background:var(--panel-2, rgba(240,233,215,.9)); border-left:2px solid var(--amber, #b9812f);
}
.issue__when{ font-size:.76rem; opacity:.55; }

/* ── wallet extras ── */
.worder__note{ display:block; font-size:.83rem; opacity:.72; margin-top:.15rem; }
.wtot__pay{ margin-top:.9rem; width:100%; }

/* ── pay sheet ── */
.paysheet__soon{
  font-size:.87rem; margin:0 0 1rem; padding:.6rem .8rem; border-radius:8px;
  background:var(--amber-soft, rgba(185,129,47,.14));
  border-left:2px solid var(--amber, #b9812f);
}
.paymethods{ list-style:none; margin:0 0 1.2rem; padding:0; display:flex; flex-direction:column; gap:.5rem; }
.paymethods li{
  display:flex; align-items:center; gap:.75rem;
  border:1px solid var(--line, rgba(35,31,22,.14)); border-radius:10px;
  padding:.7rem .85rem; background:var(--field, #fffdf6);
}
.paymethods li span:last-child{ display:flex; flex-direction:column; }
.paymethods small{ opacity:.62; font-size:.8rem; }
.paymethods__ic{
  width:2rem; height:2rem; flex:none; display:grid; place-items:center;
  border-radius:7px; background:var(--panel-2, rgba(240,233,215,.9)); opacity:.75;
}

@media (max-width:560px){
  .tline__when{ min-width:100%; }
  .tline__meta{ padding-left:0; }
}


/* The total block was a single flex row for the old one-line total. Now that it
   holds charged / paid / due as stacked rows plus a button, it has to be a column
   or the rows squash into each other. */
.wallet__total{ flex-direction:column; align-items:stretch; gap:0; }
.wallet__total .wtot__row{ font-size:.95rem; }
.wallet__total .wtot__row--due strong{ font-size:1.05rem; }

/* An amount must never break across lines: "€1,750.00" splitting after the
   symbol reads as two figures. */
.wtot__row strong,.wtot__row span:last-child{ white-space:nowrap; }
.wtot__row span:first-child{ min-width:0; }


/* ═══════════════ the onboarding ask ═══════════════
   A short, skippable modal on first sign-in. It is the only interruption in
   the portal, so it earns its place by asking for the one thing that unlocks
   the transfer, the groceries and the SIM, then getting out of the way. */

.modal__card--ob{ max-width:40rem; }
.ob__eyebrow{ font-size:.66rem; letter-spacing:.18em; text-transform:uppercase;
  color:var(--clay, #9c5b41); margin:0 0 .35rem; }
.modal__card--ob h3{ margin:0 0 .5rem; font-size:1.45rem; }
.ob__lead{ margin:0 0 1.25rem; opacity:.78; font-size:.95rem; max-width:40ch; }
.detform--ob{ background:none; border:0; border-radius:0; padding:0; margin:0; gap:.9rem; }
.ob__foot{ display:flex; gap:.7rem; flex-wrap:wrap; margin-top:.35rem; }
.ob__foot .btn{ flex:1 1 auto; }
.ob__note{ margin:.2rem 0 0; font-size:.82rem; opacity:.62; }

@media (max-width:560px){
  .ob__foot{ flex-direction:column-reverse; }   /* Save sits under the thumb */
  .ob__foot .btn{ width:100%; }
}


/* ═══════════════ one more night, and commission lines ═══════════════ */

.extend{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
  gap:1rem 1.5rem;
  border-color:var(--profit, #2f6357);
  background:linear-gradient(140deg, var(--profit-soft, rgba(47,99,87,.12)), transparent 70%);
}
.extend__body{ flex:1 1 22rem; min-width:0; }
.extend__body h3{ margin:0 0 .35rem; color:var(--profit, #2f6357); }
.extend__body p{ margin:0; max-width:46ch; }
.extend__act{ display:flex; align-items:center; gap:1rem; flex-wrap:wrap; }
.extend__price{ font-size:1.05rem; font-weight:600; white-space:nowrap; }

/* A commission booking costs the guest nothing here, so it should not read
   like a price of zero. */
.svc__free{ color:var(--profit, #2f6357); }

@media (max-width:560px){
  .extend__act{ width:100%; justify-content:space-between; }
  .extend__act .btn{ flex:1 1 auto; }
}

/* ── a note written for one stay ──────────────────────────────
   Sits at the top of Your stay, above the standing cards, because it is the
   one thing on the page that was written for this guest rather than for
   everyone. Amber edge and a warmer ground so it reads as a message rather
   than another data panel; deliberately not a full accent card, which would
   make it shout over the practical information underneath. */
.ov-card--note{
  background:linear-gradient(130deg, rgba(198,138,63,.13), rgba(198,138,63,.05));
  border-left:3px solid var(--amber);
}
.note__body p{
  margin:0 0 .8rem; max-width:var(--measure, 44rem);
  line-height:1.7;
}
.note__body p:last-child{ margin-bottom:0; }

/* ── the entry codes ──────────────────────────────────────────
   The first version was a two-column row with the label left and the value
   hard right. It read as a price list, the numerals ended up an inch from the
   thing they belonged to, and a long value like "a lock box on the lift
   landing" wrapped into the gap. Stacked instead: label above in small caps,
   value under it at reading size, so each step is one block the eye takes in
   at once. */
.keys{ list-style:none; counter-reset:k; margin:0 0 1rem; padding:0;
  display:grid; gap:.1rem; }
.keys__row{
  counter-increment:k;
  display:grid; grid-template-columns:1.6rem 1fr; align-items:baseline;
  gap:0 .7rem; padding:.7rem .85rem .7rem .6rem; border-radius:var(--r);
}
.keys__row::before{
  content:counter(k); grid-row:span 2;
  font-size:.62rem; color:var(--clay); opacity:.55;
  font-variant-numeric:tabular-nums;
}
.keys__what{
  font-size:.6rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--clay); opacity:.85;
}
.keys__val{ font-size:1rem; line-height:1.4; }
/* A code is read once, at a door, often one-handed. Give it room. */
.keys__val--code{
  font-size:1.5rem; font-weight:600; letter-spacing:.14em;
  font-variant-numeric:tabular-nums; line-height:1.25;
}
/* The lock box holds the key. It is the step people miss, so it is the step
   that gets the colour. */
.keys__row--key{
  background:linear-gradient(120deg, rgba(198,138,63,.16), rgba(198,138,63,.06));
  box-shadow:inset 3px 0 0 var(--amber);
}
.keys__row--key .keys__what{ color:var(--ink); opacity:.7; }
.keys__note{ font-size:.86rem; line-height:1.6; opacity:.72; margin:0; }

/* wifi, same treatment so the two cards read as a pair */
.wifi{ margin:0; display:grid; gap:.7rem; }
.wifi dt{
  font-size:.6rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--clay); opacity:.85; margin-bottom:.1rem;
}
.wifi dd{ margin:0; }

.ov-card--keys{ background:#f6f1e4; }
.guide__locked{ opacity:.6; }

/* ── instructional photographs ────────────────────────────────
   These were butting against the card edge and sitting flush left under
   paragraphs that have their own measure. Give the grid the same breathing
   room as the text around it, centre each figure in its column, and let the
   caption sit under the image rather than under the column. */
.howto{
  display:grid; gap:1.1rem 1.2rem; margin:1.2rem 0 .4rem;
  grid-template-columns:repeat(auto-fit, minmax(13rem, 1fr));
  align-items:start; justify-items:center;
}
.howto--one{ grid-template-columns:minmax(0, 22rem); justify-content:center; }
.howto--four{ grid-template-columns:repeat(auto-fit, minmax(11rem, 1fr)); }
.howto figure{
  margin:0; display:flex; flex-direction:column; align-items:center;
  max-width:100%;
}
.howto img{
  display:block; width:auto; max-width:100%; max-height:24rem; height:auto;
  border-radius:var(--r); border:1px solid rgba(23,21,15,.14);
  background:var(--petrol-d);
}
.howto figcaption{
  margin-top:.55rem; font-size:.8rem; line-height:1.5; opacity:.72;
  text-align:center; max-width:22rem;
}

/* ── touch targets ───────────────────────────────────────────
   Measured on a 375px screen: the tab pills came out 37px tall, Sign out 38,
   and the "open in Maps" link 38. All readable, all a little under the ~44px
   a thumb actually lands on, and the tabs are the control a guest uses most.
   Raised with min-height and centring rather than more padding, so the pill
   grows without the label moving.

   Behind (pointer: coarse) so this only applies where a finger is doing the
   pointing; a mouse does not need the extra height and the desktop layout
   stays exactly as it was. */
@media (pointer: coarse){
  .app__tabs button,
  .btn{ min-height:44px; display:inline-flex; align-items:center; justify-content:center; }
  .app__brand{ min-height:44px; display:inline-flex; align-items:center; }
  /* inline links that sit on their own line and act as buttons */
  .pane a[href^="http"],
  .pane a[href^="geo"],
  .keys a{ padding-block:.35rem; }
}
