/* Residence layer — panel tabs, media tiles, scene states, plan viewer.
   Palette and shapes follow creative-direction.css; nothing here restyles the
   region or resort scales. */

/* ---------------------------------------------------------------- tab bars */
.tabs{display:flex;flex-wrap:wrap;gap:6px;margin:16px 0 14px}
.tabs button{padding:8px 11px;border:1px solid rgba(23,37,33,.16);border-radius:999px;
  background:rgba(255,255,255,.55);color:var(--cimalpes-forest);font-size:11px;cursor:pointer}
.tabs button.active{background:var(--cimalpes-forest);color:var(--cimalpes-ivory)}
.tab-body h3{margin:20px 0 6px;font:700 11px/1 Inter,system-ui;letter-spacing:.12em;
  text-transform:uppercase;color:#7b6a47}
.tab-body>h3:first-child{margin-top:4px}
.muted{color:#71817a;font-size:12px}
.prototype-badge{margin:0 0 12px;padding:8px 11px;border-left:3px solid var(--cimalpes-gold);
  background:rgba(184,148,82,.12);border-radius:0 8px 8px 0;font-size:11px;color:#6d5c39}

/* ------------------------------------------------------------------- facts */
.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin:14px 0}
/* A column, so that a label which needs two lines ("Notaries' fees") does not
   push its own value below the values beside it. The grid stretches every fact
   to the tallest, and margin-top:auto then drops each value onto one baseline. */
.fact{padding:9px 7px;background:#fff;border-radius:10px;text-align:center;
  display:flex;flex-direction:column}
.fact small{display:block;font-size:9px;letter-spacing:.1em;text-transform:uppercase;color:#8b9691}
.fact strong{display:block;margin-top:auto;padding-top:3px;font:700 15px/1 Georgia,serif}
.highlights{margin:6px 0;padding-left:18px;color:#50625f;line-height:1.5;font-size:13px}
.highlights li{margin-bottom:5px}
.contact{padding:12px;background:#fff;border-radius:10px;display:grid;gap:4px}
.contact a{color:var(--cimalpes-clay);font-weight:600;text-decoration:none;font-size:13px}

/* ------------------------------------------------------------------- media */
.media-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:12px 0}
.media-tile{position:relative;margin:0;padding:11px;border:1px solid var(--line);
  border-radius:12px;background:#ffffffaa;display:grid;gap:4px;align-content:start}
.media-tile.splat{grid-column:1/-1;border-color:var(--cimalpes-gold);background:rgba(184,148,82,.1)}
.media-tile.empty{background:repeating-linear-gradient(45deg,#ffffff88 0 8px,#f0ece2aa 8px 16px)}
.media-kind{font:800 9px/1 Inter,system-ui;letter-spacing:.12em;text-transform:uppercase;
  color:var(--cimalpes-clay)}
.media-tile strong{font-size:12px;line-height:1.25}
.media-tile small{font-size:11px;color:#6c7a77;line-height:1.35}
/* One box for every tile, so the grid reads as a grid. A photograph fills it
   and is cropped around the focal point the admin stored; a drawing is fitted
   whole and letterboxed, because an elevation with its edges cut off is not a
   smaller drawing, it is a wrong one. residence.js sets data-fit. */
.media-tile img,.media-tile video{width:100%;border-radius:8px;display:block;
  aspect-ratio:4/3;background:#efeae0}
.media-tile[data-fit="cover"] img,.media-tile video{object-fit:cover}
.media-tile[data-fit="contain"] img{object-fit:contain}
.media-tile figcaption{display:grid;gap:3px}
/* The picture is a button that opens the gallery (issue #16). It must not add
   a box of its own: the 4:3 rules above stay on the img inside it. */
.media-open{display:block;width:100%;padding:0;margin:0;border:0;background:none;border-radius:8px;cursor:zoom-in}
.media-open:focus-visible{outline:2px solid var(--cimalpes-gold);outline-offset:2px}
.media-open:hover img{filter:brightness(1.04)}

/* ------------------------------------------------------------ photo gallery */
/* Full screen, over the header, the panel and the scene; under the feedback
   modal (60), above the buyer-link cards (55/56). One picture fitted whole,
   its name and caption under it, previous / next at the sides. */
/* Opaque, like #planViewer on a phone: at .94 the sheet behind stayed legible
   through the photo, which reads as a rendering fault, not as a modal. */
.lightbox{position:fixed;z-index:58;inset:0;display:grid;grid-template-columns:64px 1fr 64px;
  align-items:center;background:#0e1614;color:#f4f0e7;touch-action:pan-y}
.lightbox[hidden]{display:none!important}
/* The caption sits right under the picture: the picture is capped to what the
   screen leaves after the close button and the caption, not stretched to fill
   a row (which pushed the caption off the bottom at 1440x900). */
.lightbox-figure{margin:0;height:100%;display:grid;align-content:center;gap:12px;
  padding:56px 0 20px;min-width:0;box-sizing:border-box}
.lightbox-figure img{display:block;width:100%;height:auto;max-height:calc(100vh - 170px);max-height:calc(100dvh - 170px);
  object-fit:contain;user-select:none;-webkit-user-drag:none}
.lightbox-figure figcaption{display:grid;gap:4px;justify-items:center;text-align:center;padding:0 8px}
.lightbox-title{font-size:16px}
.lightbox-caption{font-size:13px;color:#c9d2cc}
.lightbox-caption:empty{display:none}
.lightbox-count{font:600 11px/1 Inter,system-ui;letter-spacing:.08em;color:#9fb0a8}
.lightbox button{border:0;background:rgba(244,240,231,.12);color:#f4f0e7;cursor:pointer;
  font:300 34px/1 Inter,system-ui;border-radius:999px}
.lightbox button:hover{background:rgba(244,240,231,.24)}
.lightbox button:focus-visible{outline:2px solid var(--cimalpes-gold);outline-offset:2px}
.lightbox-nav{width:48px;height:48px;justify-self:center}
.lightbox-close{position:absolute;top:12px;right:12px;width:44px;height:44px;font-size:28px!important}
.lightbox.single .lightbox-nav,.lightbox.single .lightbox-count{visibility:hidden}
html.lightbox-open{overflow:hidden}
@media (max-width:720px){
  /* Phone: the picture takes the full width, the arrows sit over its edges,
     and a swipe does the same job. */
  .lightbox{grid-template-columns:1fr}
  .lightbox-figure{grid-column:1;grid-row:1;padding:64px 0 calc(20px + env(safe-area-inset-bottom))}
  /* Over the picture now, so they need their own dark ground to be seen on a
     bright sky. */
  .lightbox-nav{grid-row:1;grid-column:1;z-index:1;width:40px;height:40px;font-size:28px;background:rgba(14,22,20,.6)!important}
  .lightbox-nav.prev{justify-self:start;margin-left:8px}
  .lightbox-nav.next{justify-self:end;margin-right:8px}
}
.pending{font:600 10px/1 Inter,system-ui;letter-spacing:.08em;text-transform:uppercase;color:#9aa39c}
.empty-state{padding:18px;border:1px dashed var(--line);border-radius:12px;text-align:center;
  display:grid;gap:5px;background:#ffffff66}
.empty-state strong{font-size:13px}
.empty-state small{font-size:11px;color:#71817a}

/* ------------------------------------------------------- availability list */
.count{font-size:13px;margin:0 0 4px}
.filters{grid-template-columns:1fr 1fr}
.card.amenity{cursor:default}
/* The grid's own gap separates it from the figure below now. */
.card b .status{display:inline-block;margin-right:0;padding:2px 6px;border-radius:999px;
  font:700 9px/1.5 Inter,system-ui;letter-spacing:.07em;text-transform:uppercase;vertical-align:middle}
.status.available{background:#dfe9dd;color:#31543f}
.status.reserved{background:#f4e6c8;color:#7a5c1c}
.status.sold{background:#e3e1de;color:#5c5a56}
.status.coming-soon{background:#dde8f1;color:#2f5877}
/* Sold stays listed (issue #14), and reads as gone at a glance: the whole row
   recedes and its status takes the price's place (residence.js listPrice). */
.card.is-sold{opacity:.6}
.card.is-sold strong{text-decoration:line-through;text-decoration-thickness:1px}
.card.is-sold.selected{opacity:.85}
.sold-note{margin:14px 0 0;padding:12px 14px;border-radius:12px;background:#e3e1de;
  color:#5c5a56;font-weight:650;text-align:center}
.apt-eyebrow{display:block;margin-top:16px}
.apt-eyebrow .status{margin-right:4px}

/* -------------------------------------------------------------- plan tiles */
.plan-thumb{margin:12px 0;padding:10px;border:1px solid var(--line);border-radius:12px;
  background:#fff}
.plan-thumb img{width:100%;display:block;border-radius:8px}
.schematic-svg{width:100%;height:auto;display:block}
.schematic-svg .room{fill:#f7f4ec;stroke:#314c43;stroke-width:1.5}
.schematic-svg .room.terrace{fill:#e6ece2;stroke-dasharray:5 4}
.schematic-svg .room-name{font:600 11px Inter,system-ui;fill:#314c43;text-anchor:middle}
.schematic-svg .room-area{font:500 10px Inter,system-ui;fill:#7b8a83;text-anchor:middle}

/* Elements toggled with the `hidden` attribute. An id rule with a `display`
   value outranks the UA's [hidden]{display:none}, which leaves an invisible
   overlay swallowing clicks. See MISTAKES.md M-001. */
#planViewer[hidden],#sceneStatus[hidden]{display:none!important}

/* ------------------------------------------------------------ scene states */
#sceneStatus{position:absolute;inset:0;z-index:5;display:grid;place-items:center;
  background:rgba(201,213,203,.82);backdrop-filter:blur(3px)}
.scene-note{max-width:min(430px,80%);padding:26px 30px;border-radius:20px;text-align:center;
  background:rgba(245,241,232,.96);box-shadow:0 24px 70px rgba(16,35,30,.24);display:grid;gap:8px}
.scene-note strong{font:20px/1.25 Georgia,serif}
.scene-note small{font-size:12px;color:#61716c;line-height:1.4}
.scene-note.error strong{color:var(--cimalpes-clay)}
.scene-actions{display:grid;gap:7px;margin-top:8px}
.scene-actions button{border-radius:999px;padding:11px 16px}
.spinner{width:26px;height:26px;margin:0 auto 4px;border-radius:50%;
  border:3px solid rgba(49,76,67,.2);border-top-color:var(--cimalpes-forest);
  animation:sceneSpin .9s linear infinite}
@keyframes sceneSpin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.spinner{animation-duration:2.4s}}

/* ------------------------------------------------------------- plan viewer */
/* Desktop: beside the 3D view, leaving the panel readable. Mobile: full screen.
   The two offsets are the layout tokens, never the numbers they happen to equal
   at one screen size. They were written as `68px 414px` — the laptop class's
   header height and its 370+22+22 panel edge — and responsive.css has since made
   both of them variable, so on every OTHER desktop class this dialog covered the
   thing it exists to sit beside: measured 51px of panel at 1680, 113px at 1920
   and 246px at 2560, plus 10px and 36px of the header, which it also outranks
   (z:30 over z:20). At 1440 var(--panel-edge) still computes to exactly 414px,
   so the class it WAS drawn for is unchanged. */
#planViewer{position:fixed;z-index:30;inset:var(--header-h) var(--panel-edge) 0 0;display:grid;
  grid-template-rows:auto 1fr auto;background:rgba(23,37,33,.96);color:var(--cimalpes-ivory)}
.plan-bar{display:flex;align-items:center;gap:12px;padding:12px 16px;
  border-bottom:1px solid rgba(245,241,232,.18)}
.plan-bar strong{font:600 13px/1 Inter,system-ui}
.plan-zoom{font:600 11px/1 Inter,system-ui;color:#ead7ad;min-width:44px}
.plan-controls{margin-left:auto;display:flex;gap:6px}
.plan-controls button{border:0;border-radius:8px;padding:8px 12px;background:rgba(245,241,232,.14);
  color:var(--cimalpes-ivory);font:600 12px/1 Inter,system-ui;cursor:pointer}
.plan-controls button:hover{background:rgba(245,241,232,.28)}
.plan-stage{position:relative;overflow:hidden;display:grid;place-items:center;
  touch-action:none;cursor:grab}
/* No will-change here: the canvas scales up to 6x, and promoting a layer that
   large is expensive on the low-power machines this has to run on. */
.plan-canvas{transform-origin:center;max-width:86%;max-height:86%}
.plan-canvas img{max-width:100%;max-height:80vh;display:block;user-select:none}
.plan-canvas .schematic-svg{width:min(680px,84vw)}
.plan-canvas .schematic-svg .room{fill:#f7f4ec}
.plan-note{margin:0;padding:10px 16px;font-size:11px;color:#b9c4bb;
  border-top:1px solid rgba(245,241,232,.18)}

@media (max-width:720px){
  .facts{grid-template-columns:repeat(2,1fr)}
  .media-grid{grid-template-columns:1fr}
  /* Full screen has to mean opaque. At .96 over a phone the header, the scene
     chrome and the sheet underneath were all still legible through the floor
     plan, which reads as a rendering fault rather than as a modal. */
  #planViewer{inset:0;background:#172521}
  /* A title, a zoom read-out and four controls do not fit a phone on one row:
     the title wrapped inside a bar sized for one line and overflowed it. The
     title takes its own row and the controls follow underneath. */
  .plan-bar{flex-wrap:wrap;row-gap:8px;padding:10px 14px}
  .plan-bar strong{flex:1 0 100%}
  /* Five tabs wrapped onto two rows and took 86px out of a sheet that has
     little to give. They scroll sideways instead, like .resort-categories. */
  .tabs{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;padding-bottom:4px}
  .tabs::-webkit-scrollbar{display:none}
  .tabs button{flex:0 0 auto;white-space:nowrap}
  .plan-canvas .schematic-svg{width:92vw}
  .scene-note{padding:20px 22px}
}

/* ------------------------------------------------ viewpoint / delivery card */
/* Both users of .viewpoint write <small>LABEL</small><strong>Heading</strong>
   (residence.js overviewTab and viewTab). Neither element is block-level by
   default and nothing here made them so, so the two ran together into one line
   of prose: "DELIVERY · TBCNew development" on the Overview tab and
   "VIEWPOINTLiving room mountain view" on an apartment's View tab. .spec and
   .card already declare exactly this for the same shape; .viewpoint was the one
   that did not. The label reads as an eyebrow, like .media-kind above it. */
.viewpoint small,.viewpoint strong{display:block}
.viewpoint small{font:800 9px/1.4 Inter,system-ui;letter-spacing:.12em;
  text-transform:uppercase;color:var(--cimalpes-clay)}
.viewpoint strong{margin-top:2px;font-size:13px;line-height:1.3}
.viewpoint .muted{margin:4px 0 0}
