/* ============================================================
   UNIQorn — space.css
   Inside a business entrance.

   Base is exactly var(--white) (checklist A2). Separation is always a 1px
   hairline, never a colour block.

   Three entrances, one ring. Each space draws its own line form and puts
   the single red anchor where that line lands — the same relationship the
   homepage cover shows, carried inside.

   The line carries over from the cover rather than starting again. On the
   homepage it rises out of a real room, comes to rest at the red anchor and
   frays into three strands that land on the three entrances; here it comes
   out of this space's photograph, comes to rest at the anchor, and frays into
   one strand per door. Every strand ends on the thing it names, which is what
   stops the drawing reading as decoration floating in its own band.

   Its geometry is generated (tools/space-line.py) and seated on measured DOM
   positions (assets/space.js) — see those files for why.
   ============================================================ */

:root {
  /* --anchor-red lives in foundation.css. Not re-declared here. */
  --edge-rule: 44px;
}

/* ---------- header: current-space identity ---------- */

.space-id {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin: 0;
  padding-inline-start: var(--space-5);
  border-inline-start: 1px solid var(--line);
}
.space-id-num {
  font: 500 var(--text-xs)/1 var(--font-mono);
  letter-spacing: var(--tracking-label);
  font-variant-numeric: tabular-nums;
  color: var(--indigo);
}
.space-id-name {
  font-size: var(--text-sm);
  color: var(--fg-2);
  transition: color var(--motion-fast) var(--ease-standard);
}
.space-id-name:hover { color: var(--indigo); }
/*
 * The way home. The space name is the link; 「主页」 says what the link does.
 * It is metadata, so it wears the same mono/label treatment as the number and
 * the English name, one step quieter — present, not competing with the name.
 */
.space-id-home {
  font: 500 var(--text-xs)/1 var(--font-mono);
  letter-spacing: var(--tracking-label);
  color: var(--meta);
  margin-inline-end: var(--space-2);
}
.space-id-name:hover .space-id-home { color: var(--indigo); }
.space-id-en {
  font: 500 9px/1 var(--font-mono);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--meta);
}

/*
 * Support links (About / Contact) are never peers of the business pages.
 * When a space nav is present they step aside: smaller, lighter, behind a rule.
 */
.site-header .desktop-nav + .support-nav {
  margin-left: 0;
  padding-inline-start: var(--space-6);
  border-inline-start: 1px solid var(--line);
}
.support-nav .menu { gap: 0 var(--space-4); }
.support-nav .menu a { font-size: var(--text-sm); color: var(--muted); }
.support-nav .menu a:hover { color: var(--indigo); }

/* ---------- cross-business switching: left / right edges ---------- */

.space-edges a.edge {
  /* gap and block padding both scale with --edge-w so the strip's intrinsic
     width tracks the variable across the 68->44 transition. Without this,
     `padding-block` stayed 48 while --edge-w halved — the content-box width
     then upgraded itself to 96 to fit the padding, the shell's pad-extra
     became 32 short, and the strip sat right against the text. */
  gap: var(--space-4);
  padding-block: calc(var(--edge-w) * 0.7);
}
.edge-hint {
  font-size: 10px;
  letter-spacing: .2em;
  color: var(--meta);
}
/*
 * Direction is set here, not in the markup, because the strip is vertical on
 * desktop and horizontal on small screens — the arrow has to follow the axis
 * the reader is actually moving along.
 */
.space-edges a.edge::before {
  content: "↑";
  font-size: 13px;
  line-height: 1;
  color: var(--mist);
  transition: color var(--motion-base) var(--ease-standard);
}
.space-edges a.edge--right::before { content: "↓"; }
.space-edges a.edge:hover::before { color: var(--indigo); }
.edge-rule {
  width: 1px;
  height: var(--edge-rule);
  background: var(--line);
  transition: height var(--motion-base) var(--ease-standard), background var(--motion-base) var(--ease-standard);
}
.edge-num {
  font: 500 10px/1 var(--font-mono);
  letter-spacing: var(--tracking-label);
  font-variant-numeric: tabular-nums;
  color: var(--indigo);
}
.edge-name {
  font-size: 13px;
  letter-spacing: .16em;
  color: var(--fg-2);
  transition: color var(--motion-base) var(--ease-standard);
}
.space-edges a.edge:hover .edge-name { color: var(--indigo); }
.space-edges a.edge:hover .edge-rule { height: calc(var(--edge-rule) + 18px); background: var(--indigo); }

/* A thin drawn line grows out of the edge on hover — the signature, kept alive. */
.space-edges a.edge::after {
  content: "";
  width: 1px;
  height: 0;
  background: var(--mist);
  transition: height var(--motion-slow) var(--ease-flow);
}
.space-edges a.edge:hover::after { height: 72px; }

/* ---------- space landing ---------- */

.page-main--space { padding-block: clamp(40px, 6vw, 88px) clamp(56px, 8vw, 104px); }

/*
 * One positioning context for the whole drawing. The stage spans the heading,
 * the photograph and the doors, so the line can be measured against all three
 * in a single coordinate system — which is the only way a strand that starts
 * on the photograph can be guaranteed to end on a door.
 */
.space-stage {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
  column-gap: clamp(24px, 4.5vw, 76px);
  row-gap: clamp(24px, 3.5vw, 48px);
  align-items: start;
}

/* ---------- the heading ---------- */

.space-hero {
  grid-column: 1;
  grid-row: 1;
  position: relative;
  z-index: 3;
}
.space-hero-place { margin-bottom: var(--space-8); }
.space-hero-num {
  margin: 0 0 var(--space-4);
  font: 500 clamp(22px, 2.6vw, 32px)/1 var(--font-mono);
  letter-spacing: .2em;
  font-variant-numeric: tabular-nums;
  color: var(--mist);
}
.space-hero-title { margin: 0; }
.space-hero-en {
  margin: var(--space-5) 0 0;
  /*
   * Sized to sit as a quiet subtitle rather than a second eyebrow. The hero
   * already carries one tracking label (the place strip); an equally-heavy
   * second label turns the stack into two eyebrows, which the binding §4.2
   * flags as a §4.7 layout-family mistake.
   */
  font: 400 10.5px/1.4 var(--font-mono);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--muted);
}
/*
 * Wide enough that the sentence's own break is the only break. `.lede`'s 62ch
 * default is measured in Latin characters and comes out far too narrow for
 * Chinese, which then wraps a second time and undoes the authored break.
 */
.space-hero-lede { margin: var(--space-8) 0 0; max-width: 26em; }

/* ---------- the anchor sentence (tarot only today) ---------- */

/*
 * A pull-quote that sits between the hero and the photograph, full width.
 *
 * Italic serif, set in Noto Serif SC 300. The font is already the brand's
 * display face (uniqorn-taste §3), so no extra import is needed. Letter
 * spacing is slightly opened because italic Serif SC at this scale can read
 * as a wall of strokes otherwise.
 *
 * The red dot rides on the first glyph as the same anchor the drawn line in
 * the stage uses to mark "this is the place the strand lands" — connecting
 * the page's sentence to the line form above.
 */
.space-anchor-quote {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: clamp(12px, 1.6vw, 24px);
  align-items: start;
  margin: clamp(20px, 3.2vw, 44px) 0 0;
  padding-block: clamp(8px, 1.4vw, 18px);
  border-block: 1px solid color-mix(in oklab, var(--indigo) 16%, transparent);
}
.space-anchor-dot {
  /*
   * 6px red dot, optically aligned to the cap-height of the first glyph.
   * margin-top nudges it down by roughly a third of the italic serif's
   * ascender, so it sits where the line would naturally arrive.
   */
  display: block;
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--anchor-red);
  margin-top: clamp(14px, 1.8vw, 22px);
}
.space-anchor-text {
  margin: 0;
  /*
   * The font shorthand is split so the italic axis is never lost to a token
   * fall-through. `font: italic 300 .../... ...` parses fine when the family
   * resolves, but if the family falls back to system-ui the italic face is
   * synthesized into nothing.
   */
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(20px, 2.4vw, 30px);
  line-height: 1.45;
  letter-spacing: 0.04em;
  color: var(--fg);
  max-width: 28em;
}

/* ---------- the photograph ---------- */

/*
 * The same generated field the cover photograph uses, so a space reads as the
 * same world one page in rather than as a new one. `mask-size: 100% 100%`
 * stretches the field to whatever box this is; it is a smooth field with no
 * content awareness, which is exactly what makes that safe.
 *
 * It bleeds past the container's right padding — the cover photograph bleeds
 * off the lower-left corner, and the two together give the pair of pages one
 * composition. A negative margin of exactly the gutter reaches the shell's
 * padding-box edge, which is inside the viewport, so nothing overflows.
 */
.space-figure {
  grid-column: 2;
  grid-row: 1;
  position: relative;
  z-index: 1;
  margin: 0 calc(-1 * var(--gutter)) 0 0;
  /*
   * Wide, not tall. A 4:3 photograph stood taller than the heading beside it,
   * which pushed the whole door list down and left a band of nothing between
   * the two — and a band of nothing is exactly what a drawn line looks
   * stranded in. Matching the photograph's height to the heading's keeps the
   * page tight and gives the strand a short, deliberate distance to cross.
   */
  aspect-ratio: 16 / 9;
  overflow: hidden;
  mask-image: url("img/photo-dissolve.png");
  mask-size: 100% 100%;
  mask-repeat: no-repeat;
  -webkit-mask-image: url("img/photo-dissolve.png");
  -webkit-mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
}
.space-figure img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 54% 40%;
  /*
   * The cover's photograph sits on a dark ground and reads at .80 opacity. This
   * one sits on pure white, and a bright room dissolves into a bright page —
   * the field is doing its job and the picture still disappears. Two levers,
   * both needed: pull the tone down so it reads as a photograph on white rather
   * than as a stain, and push in past the field's soft shoulder so the subject
   * fills the part of the box that is actually opaque. The box clips, the field
   * fades, and the two together keep the picture from being a pale smudge.
   */
  filter: saturate(.9) contrast(1.05) brightness(.94);
  transform: scale(1.3);
  transform-origin: 54% 44%;
}

/* ---------- the drawn line ---------- */

.space-drawn {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}
.space-fan {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/*
 * A hairline at any size: the svg is stretched over the stage with
 * `preserveAspectRatio="none"`, so without `vector-effect` the stroke would be
 * scaled by a different factor on each axis and stop being 1px.
 *
 * `--line-len` is set by space.js from the measured *screen* length of each
 * path, which is what a non-scaling stroke reads its dash pattern in. Without
 * the script the property is absent, the dash is `none`, and the line is simply
 * solid — never dashed, and never missing.
 */
.space-line {
  fill: none;
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: var(--line-len, none);
  stroke-dashoffset: var(--line-len, 0);
}
/*
 * The belly: a wider stroke under the hairline, painted first. Its gradient
 * peaks in the middle of the path and falls to nothing at both ends, so the
 * line gains weight where it travels and thins where it dissolves. A constant
 * stroke width is what makes a line read as a printed trace.
 */
.space-line--belly { stroke-width: 2.3; }

.space-tick {
  fill: none;
  stroke: var(--indigo);
  stroke-opacity: .30;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/*
 * The anchor. It sits at the top of the door list, in the gutter the strands
 * fan out across, and it is where every line on this page either ends or
 * begins — the one point they share.
 */
.space-anchor {
  position: absolute;
  left: calc(var(--fan-gutter) * .72);
  top: 0;
  z-index: 4;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--anchor-red);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, .62),
    0 0 14px 3px rgba(197, 139, 142, .30);
  transform: translate(-50%, -50%) scale(1);
}

/* ---------- the doors ---------- */

/*
 * `--fan-gutter` is the line's column and the doors' left inset — one number,
 * so the line and the list agree about where the page begins. The rows used to
 * step inward one after another to give a fan room to reach them; with the fan
 * gone there is nothing to reach for, so they line up.
 */
.space-fan-zone {
  grid-column: 1 / -1;
  grid-row: 2;
  position: relative;
  z-index: 3;
  --fan-gutter: clamp(38px, 4.6vw, 64px);
  --fan-step: 0px;
  padding-block-start: clamp(18px, 2.6vw, 36px);
}

.space-doors { margin: 0; }
/*
 * Read against the ten reference sites (tools/scrape-reference-sites.mjs): this
 * list was the busiest thing on any of the eleven pages. Each row carried four
 * text elements — a number, a label, a Latin label and a description — inside a
 * fold that every one of the references gives to a single statement. The
 * numbers are gone (Wallance's own rule from the cover: 入口不需要编号), the row
 * gets real room, and the label is set at a size that lets the four read as one
 * typographic block rather than as four lines of a table.
 */
.door {
  --door-in: calc(var(--fan-gutter) + var(--fan-step) * var(--i, 0));
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--space-3) var(--space-8);
  padding-block: clamp(24px, 3.2vw, 46px);
  padding-inline: var(--door-in) var(--space-3);
  transition: background var(--motion-base) var(--ease-standard);
}
/*
 * A rule above and below each row.
 *
 * Removing them was tried and put back. The reasoning was that the first fold
 * was cut into eight bands of content where the reference set's median is four,
 * and the rules looked like the cause — but the fold analysis counts a band as
 * a run of rows with any ink in them, and a 1px hairline at var(--line) does not
 * survive the downscale, so the rules were never being counted at all. Removing
 * them left the count at seven and left the four labels floating with their
 * descriptions orphaned under them. **The measurement did not support the
 * change and neither did the page.**
 */
.door::before,
.door:last-child::after {
  content: "";
  position: absolute;
  left: var(--door-in);
  right: 0;
  height: 1px;
  background: var(--line);
}
.door::before { top: 0; }
.door:last-child::after { bottom: 0; }
.door:hover { background: linear-gradient(90deg, var(--line-soft), transparent 58%); }

.door-body { display: block; }
.door-label {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(24px, 3.2vw, 44px);
  line-height: 1.18;
  letter-spacing: .01em;
  color: var(--fg);
  transition: color var(--motion-base) var(--ease-standard);
}
.door-en {
  display: block;
  margin-top: var(--space-3);
  font: 500 10px/1 var(--font-mono);
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--meta);
}
.door-desc {
  display: block;
  margin-top: var(--space-4);
  max-width: 42ch;
  font-size: 13px;
  line-height: 1.7;
  color: var(--meta);
}
.door-go {
  font-size: var(--text-base);
  color: var(--mist);
  transition: transform var(--motion-base) var(--ease-standard), color var(--motion-base) var(--ease-standard);
}
.door:hover .door-go { transform: translateX(6px); color: var(--indigo); }
.door:hover .door-label { color: var(--indigo); }

/* A door whose page is not published yet: shown, not linked, never a dead end. */
.door.is-pending { cursor: default; }
.door.is-pending .door-label { color: var(--muted); }
.door-status {
  align-self: center;
  padding: 3px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  color: var(--meta);
  white-space: nowrap;
}

.space-note {
  margin: 0;
  max-width: 48ch;
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
  color: var(--meta);
  font-size: 13px;
  line-height: 1.7;
}
.space-body { margin-top: var(--space-18); }

/* ---------- the draw ---------- */

/*
 * Everything hangs off `.is-live`, which space.js adds only after it has
 * measured the path and only when motion is welcome. If the script never runs,
 * or the visitor has asked for reduced motion, the drawing is already
 * complete — drawn, not mid-draw.
 *
 * One stroke, so there is only one beat: it leaves the photograph, and the
 * point opens as it arrives.
 */
.space-landing.is-live .space-line { animation: space-draw .9s var(--ease-flow) forwards; }
.space-landing.is-live .space-tick { animation: space-tick-in .5s var(--ease-flow) .8s forwards; }
.space-landing.is-live .space-anchor {
  transform: translate(-50%, -50%) scale(.2);
  animation: space-anchor-in .5s var(--ease-flow) .6s forwards;
}
@keyframes space-draw { to { stroke-dashoffset: 0; } }
@keyframes space-tick-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes space-anchor-in { to { transform: translate(-50%, -50%) scale(1); } }

/* ---------- responsive ---------- */

@media (max-width: 860px) {
  .space-edges a.edge {
    gap: var(--space-2);
    padding-block: 0;
  }
  .space-edges a.edge--left::before { content: "←"; }
  .space-edges a.edge--right::before { content: "→"; }
  .edge-hint { display: none; }
  .edge-rule { display: none; }
  .space-edges a.edge::after { display: none; }
  .edge-en { display: none; }
  .edge-name { font-size: 13px; letter-spacing: .06em; }
  .edge--left  { margin-inline-end: auto; }
  .edge--right { margin-inline-start: auto; }

  /*
   * One column: identity, then the photograph, then the doors. The line stays —
   * it is the page's structure, not its decoration — but the fan tightens so
   * the strands still fit inside the gutter at 390px.
   */
  .space-stage { grid-template-columns: minmax(0, 1fr); }
  .space-hero { grid-column: 1; grid-row: 1; }
  .space-hero-lede { max-width: 46ch; }
  .space-figure {
    grid-column: 1;
    grid-row: 2;
    margin-inline-end: 0;
    aspect-ratio: 16 / 10;
  }
  .space-fan-zone {
    grid-row: 3;
    --fan-gutter: clamp(30px, 9vw, 48px);
  }
}

@media (max-width: 768px) {
  /* Keep the space name on small screens — knowing where you are is the point. */
  .space-id { margin-left: auto; padding-inline-start: var(--space-4); border: 0; gap: var(--space-2); }
  .space-id-name { font-size: var(--text-sm); }
  .space-id-en { display: none; }
  /* the inline support nav is duplicated inside the collapsed menu */
  .site-header .desktop-nav + .support-nav { display: none; }
  .mobile-support { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--line-soft); }
  .mobile-support .menu a { font-size: var(--text-sm); color: var(--muted); }
  .door {
    gap: var(--space-2) var(--space-4);
    padding-block: clamp(20px, 6vw, 32px);
  }
  .door-desc { font-size: var(--text-sm); }
}

@media (prefers-reduced-motion: reduce) {
  .space-line,
  .space-tick,
  .space-anchor { animation: none; }
  .space-line { stroke-dasharray: none; stroke-dashoffset: 0; }
  .space-tick { opacity: 1; }
  .space-anchor { transform: translate(-50%, -50%) scale(1); }
}

/*
 * The one booking action in the Tarot & Akashic Header: the rose water-drop
 * anchor ahead of the word, nothing filled. It sits after the support links
 * and is repeated inside the mobile menu.
 */
.space-cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  flex-shrink: 0;
  font-size: 13px;
  color: var(--indigo);
  text-decoration: none;
  white-space: nowrap;
}
.space-cta-dot {
  width: 9px;
  height: 9px;
  background: var(--rose);
  border-radius: 54% 46% 58% 42%;
  transition: transform var(--motion-fast) var(--ease-standard);
}
.space-cta:hover .space-cta-dot,
.space-cta:focus-visible .space-cta-dot { transform: scale(1.3); }
.site-header-inner > .space-cta { padding-inline-start: var(--space-4); }
.mobile-navigation .space-cta { margin-top: var(--space-3); }
@media (max-width: 768px) {
  .site-header-inner > .space-cta { display: none; }
}

div.showing__more {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
}
