/* The station surface, beyond what app.css already reflows.

   Everything here is scoped to [data-surface="station"]. The web build shares
   this stylesheet and must not gain a single rule from it — the attract screen
   in a browser tab would be a full-screen overlay nobody asked for.

   The panel is 1080x1920 portrait. That is taller than it is wide by nearly
   two to one, so vertical space is the cheap axis and horizontal space is the
   expensive one: type goes up, columns stay at one. */

/* ---------- the attract screen ----------

   Dark, unlike the rest of the house. The storefront is ivory and reads as
   paper; the attract loop has to read across a room, at an angle, against
   boutique lighting, and ivory at 1920px tall is a lightbox. Ink with gold is
   the same brand with the contrast the other way up. */

.attract { display: none; }

[data-surface="station"] .attract {
  display: grid;
  position: fixed;
  inset: 0;
  z-index: 3000;
  grid-template-rows: auto 1fr auto auto;
  gap: 0;
  background:
    radial-gradient(120% 60% at 50% 0%, rgba(176,141,87,.20), transparent 60%),
    linear-gradient(180deg, var(--vs-ink-2) 0%, #0D0B08 100%);
  color: var(--vs-ivory);
  text-align: center;
  cursor: pointer;
  outline: none;
  overscroll-behavior: none;
}

/* `hidden` has to beat the rule above, and it must not be left to the browser
   to decide that. Blink's UA sheet marks [hidden] !important so it wins there,
   and the device this ships on is WebView2 — but kiosk-boot also recognises a
   WKWebView host, and WebKit's UA rule is not important, so a station on that
   engine would show an attract screen that never comes down. That is a bricked
   kiosk, and it costs one line to make impossible. */
[data-surface="station"] .attract[hidden] { display: none; }

/* The page behind must not scroll while the attract screen is up: a guest who
   drags on the overlay and moves the storefront underneath it sees the kiosk
   twitch for no reason they can explain. */
html.attract-up[data-surface="station"],
html.attract-up[data-surface="station"] body { overflow: hidden; height: 100%; }

.at-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 64px 0 28px;
}
.at-head img { width: 46px; height: 46px; opacity: .92; }
.at-head .wm {
  font-family: var(--font-display);
  font-size: 44px;
  letter-spacing: .10em;
  text-transform: uppercase;
  color: var(--vs-ivory);
}

/* ---------- the film ----------

   One slide is visible at a time and they cross-fade. Stacked in a grid cell
   rather than absolutely positioned, so the row height is the tallest slide
   and nothing shifts as they change. */

.at-film {
  display: grid;
  place-items: center;
  position: relative;
  margin: 0 72px;
  min-height: 0;
}
.at-slide {
  grid-area: 1 / 1;
  margin: 0;
  width: 100%;
  opacity: 0;
  transition: opacity 900ms ease;
  will-change: opacity;
}
.at-slide.on { opacity: 1; }
.at-slide img {
  width: 100%;
  height: 780px;
  object-fit: cover;
  border-radius: 6px;
  /* A hairline of gold rather than a border: at this size a 1px line reads as
     framing, a 2px one reads as a bezel. */
  box-shadow: 0 0 0 1px var(--vs-line), 0 40px 80px rgba(0,0,0,.5);
  filter: saturate(.96) contrast(1.02);
}
.at-slide figcaption {
  margin-top: 26px;
  font-family: var(--font-body);
  font-size: 17px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--vs-gold-light);
}

/* ---------- the invitation ---------- */

.at-copy { padding: 54px 90px 0; }
.at-copy h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 88px;
  line-height: 1.04;
  letter-spacing: -.01em;
}
.at-copy h1 em { font-style: italic; color: var(--vs-gold-light); }
.at-copy p {
  margin: 26px auto 0;
  /* Wide enough that the two sentences break where the sense does. At 24ch
     they broke mid-clause and the invitation read as three ragged lines. */
  max-width: 34ch;
  font-family: var(--font-body);
  font-size: 23px;
  line-height: 1.5;
  color: rgba(250,247,242,.72);
}

.at-cta {
  display: inline-grid;
  place-items: center;
  position: relative;
  margin: 58px auto 0;
  padding: 26px 64px;
  border: 1px solid var(--vs-gold);
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 24px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--vs-ivory);
  background: rgba(176,141,87,.12);
}
/* A ring that leaves the pill on a slow pulse. It is the only motion on the
   screen between slide changes and it is what makes a lit panel read as
   awake rather than as a poster. */
.at-cta::after {
  content: "";
  position: absolute;
  inset: -2px;
  border: 1px solid var(--vs-gold);
  border-radius: 999px;
  animation: at-pulse 2.6s ease-out infinite;
}
@keyframes at-pulse {
  0%   { transform: scale(1);    opacity: .75; }
  70%  { transform: scale(1.14); opacity: 0; }
  100% { transform: scale(1.14); opacity: 0; }
}

/* The press. Confirms the touch landed before the storefront replaces it. */
.attract.is-starting .at-cta { background: var(--vs-gold); color: var(--vs-ink-2); }
.attract.is-starting .at-cta::after { animation: none; opacity: 0; }

/* The AI disclosure follows the guest onto the attract screen. It is the first
   thing on the kiosk and it is the screen a passer-by actually reads, so
   leaving it behind on the storefront would put it exactly where nobody is. */
.at-fine {
  padding: 46px 120px 64px;
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.6;
  color: rgba(250,247,242,.42);
}

/* Shorter panels — the emulator, a windowed host, a developer's laptop in a
   portrait viewport — lose the film first. The invitation is what matters. */
@media (max-height: 1500px) {
  [data-surface="station"] .at-head { padding-top: 40px; }
  [data-surface="station"] .at-slide img { height: 42vh; }
  [data-surface="station"] .at-copy h1 { font-size: 62px; }
  [data-surface="station"] .at-copy p { font-size: 20px; }
  [data-surface="station"] .at-cta { margin-top: 38px; padding: 20px 48px; font-size: 20px; }
  [data-surface="station"] .at-fine { padding: 30px 80px 40px; font-size: 13px; }
}

/* ---------- the storefront, once the guest is in ----------

   app.css already drops the marketing bands and sizes the touch targets. What
   is left is the difference between a page that has been made bigger and one
   that was laid out for a panel you stand in front of. */

/* The page has to FILL the panel.

   A web page ends where its content ends and the browser shows nothing below
   it. A kiosk has no "below" — the panel is 1920px tall and whatever the page
   does not occupy is a dead ivory band, which on a lit screen reads as the
   site having failed to load the rest of itself. With the marketing bands
   dropped the storefront ended around 1400px and left exactly that.

   So the column stretches and the builder takes the slack: the strand gets the
   extra height, which is the one thing on this screen that benefits from it. */
[data-surface="station"] .shop-viewport {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
[data-surface="station"] #view-shop { flex: 1 1 auto; display: flex; flex-direction: column; }
[data-surface="station"] .cb-frame { flex: 1 1 auto; display: flex; }
/* The slack goes to the PANEL, not the strand. The strand SVG is capped at
   420px by the house's own stylesheet, so giving it the extra height just
   surrounds a small circle with 700px of empty gradient — which reads as a
   half-rendered page. An options list with room to breathe does not, and on a
   touch panel the rows are what a guest is actually aiming at. */
[data-surface="station"] .cb { flex: 1 1 auto; grid-template-rows: 1fr 1fr auto; }
[data-surface="station"] .cb-panel { display: flex; flex-direction: column; }
[data-surface="station"] .cb-pane.active { flex: 1 1 auto; }
/* The slack is split between the two rather than pooled in one, and the rows
   themselves grow into their share: the Base pane holds three options, and
   three normal-height rows above 400px of nothing is the same empty screen
   moved indoors. At this size they are also simply easier to hit. */
[data-surface="station"] .base-opt { min-height: 96px; }
[data-surface="station"] .charm-card { min-height: 76px; }
/* The disclosure sits last and stays put — it must not float into the middle
   of the panel when a short view leaves room above it. */
[data-surface="station"] .disclosure { margin-top: auto; }

/* The nav loses its links on portrait (the agent is the navigation), which
   leaves the bag and the guest chip sitting alone at 84px tall. Give them the
   weight of a control bar instead. */
[data-surface="station"] .sn-ico { gap: 18px; font-size: 19px; }
[data-surface="station"] .guest-chip { font-size: 17px; padding: 8px 16px; }

/* The builder is the first screen and its own header is redundant with the
   band above it. */
[data-surface="station"] .cb-sub { font-size: 18px; }
[data-surface="station"] .cb-canvas { min-height: 420px; }
[data-surface="station"] .cb-meter .mtxt { font-size: 16px; }

/* Anything Odette puts on the stage is the answer to something the guest just
   said out loud, so it gets the room to be read from standing height. */
[data-surface="station"] .stage { font-size: 18px; }
[data-surface="station"] .grid { grid-template-columns: repeat(2, 1fr); gap: 20px; }
[data-surface="station"] .piece-name { font-size: 22px; }
[data-surface="station"] .piece-price { font-size: 19px; }
[data-surface="station"] .stage-label { font-size: 15px; letter-spacing: .2em; }

/* There is no keyboard on a public screen. The appointment form is reachable
   from the storefront and from Odette, and on the kiosk she books it herself
   by voice — so the modal's typed fields are not offered here. */
[data-surface="station"] .modal { align-items: center; }
[data-surface="station"] .modal-card { max-width: 860px; font-size: 18px; }

/* The native avatar is composited over the bottom of the panel on some
   hardware. Nothing is known about how much it covers, so the page reserves a
   single variable's worth of space and that variable is 0 until a device says
   otherwise — see tokens.css. */
[data-surface="station"] body { padding-bottom: var(--station-safe-bottom); }

/* ---------- the storefront, at arm's length ----------

   The web page rendered verbatim on the panel reads as a website in a dark
   frame: transparent body letterboxing the 1100px cap against whatever the
   host paints behind it, an 11px marketing strip on top, 44px hero pills. The
   panel is read standing, at arm's length, so everything the hand or eye is
   meant to land on gets kiosk sizes — scoped to the station, the web build
   keeps the blueprint's own measurements. */

/* Nothing behind the page may ever show. The cap centres the column; the
   ivory must still run to every edge. */
[data-surface="station"] body { background: var(--vs-ivory); }

/* The website's anno strip is replaced by the voice hint. */
.station-hint { display: none; }
[data-surface="station"] .shop-anno { display: none; }
[data-surface="station"] .station-hint {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  height: 44px;
  /* The strip runs to the panel's edges even when the host window is wider
     than the viewport cap — a bar that stops mid-air reads as a glitch. */
  width: 100vw; margin-left: calc(50% - 50vw);
  /* Light, per the draft — guidance in the house's own voice, not a banner. */
  background: var(--vs-ivory-2);
  color: var(--vs-ink);
  border-bottom: 1px solid rgba(35,32,28,.08);
  font-size: 15px; letter-spacing: .04em;
}

/* Hero: the first thing a guest reads, from a metre away.

   It owns the whole first screen — hint strip (44) + nav (84) + hero = one
   panel exactly, so the fold lands on the hero photo's bottom edge and never
   through a row of category tiles. A photo cut mid-tile reads as an accident;
   a photo that ends at the screen's edge reads as composed. The copy is
   centred: in portrait this screen is a poster, not a paragraph. */

[data-surface="station"] .sh-copy {
  text-align: center;
  align-items: center;
  padding: 88px 46px 64px;
}
[data-surface="station"] .sh-copy p { margin-inline: auto; }
[data-surface="station"] .sh-img {
  width: 100%; height: 474px;
  min-height: 0; max-height: none;   /* the portrait 42vh cap is the web's */
  object-fit: cover;
}
[data-surface="station"] .sh-copy h3 { font-size: 54px; }
[data-surface="station"] .sh-copy p { font-size: 19px; max-width: 54ch; }
[data-surface="station"] .sh-btns { gap: 16px; margin-top: 16px; justify-content: center; }
[data-surface="station"] .sh-btns .b1,
[data-surface="station"] .sh-btns .b2 {
  font-size: 18px; padding: 19px 38px; min-height: 60px;
  display: inline-flex; align-items: center;
}

/* Tiles and cards: labels readable, targets generous. */
[data-surface="station"] .cat-label { font-size: 20px; }
/* Row gap beats column gap by 10px so the fold can hold a sliver of ivory
   under the first tile row without the second row's top edge creeping in. */
[data-surface="station"] .shop-cats { gap: 28px 18px; }
[data-surface="station"] .sp-copy h4 { font-size: 28px; }
[data-surface="station"] .sp-copy p { font-size: 16px; }
[data-surface="station"] .sp-btn { font-size: 17px; padding: 16px 30px; }
[data-surface="station"] .st-item { font-size: 16px; }

/* The draft's nav: the four links earn their place on the kiosk — each is a
   real tap target that drives a tool — so the portrait rule that hides them
   (written for phones) is lifted here. */
[data-surface="station"] .sn-links { display: flex; gap: 30px; }
[data-surface="station"] .sn-links a { font-size: 17px; }

/* Four promises in one row, as drawn; the portrait 2x2 is for phones. */
[data-surface="station"] .shop-trust { grid-template-columns: repeat(4, 1fr); }
[data-surface="station"] .st-item:nth-child(3) { border-left: 1px solid rgba(35,32,28,.10); }
[data-surface="station"] .st-item { font-size: 14px; }

[data-surface="station"] .cat-copy .cat-label { font-size: 32px; }
[data-surface="station"] .cat-sub { font-size: 15px; }
[data-surface="station"] .how-head h3 { font-size: 30px; }
[data-surface="station"] .how-steps li { font-size: 15px; }
[data-surface="station"] .sh-caption { font-size: 28px; }
[data-surface="station"] .sa-copy h3 { font-size: 27px; }

/* The kiosk is read at arm's length; its comparison cards may run larger
   than the web's cap, but not unbounded. */
[data-surface="station"] .compare { grid-template-columns: repeat(auto-fit, minmax(240px, 470px)); }
