/* The /fun index is a room.
 *
 * It loads fun.css first for the tokens and the two typefaces, then overrides
 * almost everything structural, because a room shares nothing with a page: no
 * measure, no rhythm, no header, no footer. Shaun's brief was "the WHOLE page
 * has to be a room, which means lose the footer, the header, and so it FEELS
 * like you're in the room."
 *
 * HOW IT IS BUILT
 *
 * One background plate holds the fixed furniture: walls, floor, rug, the
 * bookcase carcass with bare shelves, the door, and the cupboard that the bureau
 * is composited over. It is generated
 * once and changes almost never. Everything that can be clicked is a separate
 * small plate composited on top at a known percentage coordinate. Adding a
 * thing to the room later is one more drawing and one more anchor, never a
 * redraw of the scene, which is what the section's own promise ("things get
 * added when they get made") requires.
 *
 * The anchor IS the manifest. Position, size, artwork, label and destination
 * all live on one element, so the clickable layer and the drawn layer cannot
 * drift apart: they are the same thing. An earlier plan kept a JS array of
 * coordinates and rendered anchors from it, which would have made the room
 * JS-dependent and put two copies of the truth in the file.
 *
 * WHY THE PLATE HAS NO VISIBLE EDGE
 *
 * scripts/plate-process.py redraws every plate as a duotone between --paper
 * and --ink, so the drawing's paper IS this page's background. The scene is
 * sized to fit inside the viewport rather than cropped to fill it, and on a
 * screen shaped differently from the plate the leftover is the same cream as
 * the drawing. There is no letterbox to see. Fitting rather than cropping also
 * means no object is ever clipped off the edge on an unusual screen, which a
 * cover-fill would risk on every phone held sideways.
 */

/* ---- structural overrides on fun.css ---- */

html, body { height: 100%; }

.room-body {
  margin: 0;
  background: var(--paper);
}

.room-body main {
  max-width: none;
  margin: 0;
  padding: 0;
  height: 100%;
  display: grid;
  place-items: center;
}

/* .vh lives in fun.css: the bookcase needs it too. */

/* ---- the scene ---- */

.room-scene {
  /* The largest box of the plate's shape that fits the viewport. Every hotspot
     is positioned in percentages of this box, so the coordinates hold at any
     size without a single line of JavaScript. */
  --scene-w: min(100vw, calc(100vh * 1740 / 1024));
  /* Bounds in rem rather than px so a reader who has raised their browser's
     font size gets larger labels; the middle term still tracks the scene. */
  --tag-size: clamp(0.66rem, calc(var(--scene-w) * 0.0092), 0.94rem);

  /* Where the ROOM sits inside the plate, printed by scripts/plate-process.py
     when it extends the canvas. The drawing is 1536x1024; the shipped plate is
     1740x1024, the extra being clamped wall and floor that fades out so the
     room does not stop dead against blank page on a screen shaped differently
     from the drawing.

     Every coordinate in the page is written against the ROOM, read straight off
     a percentage grid laid over the drawing, and these four numbers map it onto
     the plate. Bake the padding into the coordinates instead and the next
     person to move a book has to reverse-engineer why the door starts at 6.8%
     of nothing in particular. */
  --pad-x: 5.862%;
  --pad-y: 0%;
  --span-x: 0.88276;
  --span-y: 1;
  /* The drawing inside the plate. A consistent but wrong pad/span pair would
     otherwise satisfy every check; this ties them to the actual asset. */
  --art-w: 1536;
  --art-h: 1024;

  position: relative;
  width: var(--scene-w);
  aspect-ratio: 1740 / 1024;
  line-height: 0;
}

/* svh rather than vh keeps the room fitting while a phone's URL bar is showing.
   It has to be an @supports block: the usual trick of declaring the property
   twice does nothing here, because a custom property accepts any token stream,
   so the svh line would win even where the unit is unknown and the page would
   fall back to width:auto rather than to the vh line above. */
@supports (height: 100svh) {
  .room-scene { --scene-w: min(100vw, calc(100svh * 1740 / 1024)); }
}

/* picture is inline by default, so the img's height:100% would resolve against
   an auto-height box and collapse. */
.room-scene > picture {
  display: block;
  width: 100%;
  height: 100%;
}

.room-plate {
  display: block;
  width: 100%;
  height: 100%;
  /* The plate and the scene are the same shape by construction; cover is here
     so a future re-crop degrades into a small trim rather than a stretch. */
  object-fit: cover;
  user-select: none;
  -webkit-user-drag: none;
}

/* ---- the things in the room ---- */

/* --x/--b/--w place a thing on the wide plate, --tx/--tb/--tw on the tall one.
   --h/--th are for things that are already drawn into the background plate and
   need a hit area rather than artwork of their own: the door. Everything else
   takes its height from the artwork's own proportions, so resizing an object
   can never squash it. */
.thing {
  position: absolute;
  left: calc(var(--pad-x) + var(--x) * var(--span-x));
  bottom: calc(var(--pad-y) + var(--b) * var(--span-y));
  width: calc(var(--w) * var(--span-x));
  height: auto;
  display: block;
  text-decoration: none;
  z-index: 2;
}

/* Only a hit area declares its own height; artwork takes its height from its
   own proportions so resizing an object can never squash it. */
.thing-area { height: calc(var(--h) * var(--span-y)); }

.thing-art {
  display: block;
  width: 100%;
  height: auto;
  transition: transform .22s ease;
}

.thing:hover .thing-art,
.thing:focus-visible .thing-art { transform: translateY(-2.2%); }

/* A hit area over furniture that the background plate already draws. Invisible
   until it is wanted, then it warms rather than outlines, so the door reads as
   lit rather than as a form control sitting on a drawing. */
.thing-area {
  border-radius: 2px;
  background: transparent;
  transition: background .22s ease;
}
.thing-area:hover, .thing-area:focus-visible { background: rgba(223, 89, 17, .09); }

.thing:focus-visible {
  outline: 3px solid var(--orange);
  outline-offset: 4px;
  border-radius: 2px;
}

/* ---- the labels ---- */

/* Always visible, on every device.
 *
 * Reveal-on-hover was the obvious move and it is wrong twice over. A touch
 * screen has no hover, so every label would need a first tap to appear and a
 * second to follow, and the standing rule for this site is never to make
 * someone confirm a choice they have already made. And a room of unlabelled
 * pictures gives no sign that any of it is clickable. Permanent labels turn
 * that problem into the idea: the room reads as an exhibit, and every exhibit
 * is a link. */
.tag {
  position: absolute;
  z-index: 3;
  font-family: var(--font-mono);
  font-size: var(--tag-size);
  letter-spacing: .09em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  color: var(--ink-2);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: .45em .6em;
  transition: color .18s, border-color .18s;
}
.tag i { font-style: normal; margin-right: .35em; }

.thing:hover .tag,
.thing:focus-visible .tag { color: var(--orange-deep); border-color: var(--orange); }

.thing[data-tag="right"] .tag { left: 100%; margin-left: .6em; top: 50%; transform: translateY(-50%); }
.thing[data-tag="below"] .tag { top: 100%; margin-top: .5em; left: 50%; transform: translateX(-50%); }
.thing[data-tag="above"] .tag { bottom: 100%; margin-bottom: .5em; left: 50%; transform: translateX(-50%); }
/* On the object itself, which is how a sign on a door works. */
.thing[data-tag~="on"] .tag { left: 50%; top: 30%; transform: translate(-50%, -50%); }

/* ---- portrait ---- */

/* A wide interior at 390px is the whole risk of this design, so it gets its
   own plate rather than a squeezed version of the wide one: the same room,
   redrawn upright, with the bookcase and bureau side by side and the rug
   filling the foreground. The <picture> element swaps the drawing and this
   block swaps the coordinates, both on the same query, so they cannot
   disagree about which room is on screen. */
@media (max-aspect-ratio: 1 / 1) {
  .room-scene {
    --scene-w: min(100vw, calc(100vh * 768 / 1536));
    /* A phone-width scene needs a much larger share of its own width to reach
       a legible label than a laptop-width one does. */
    --tag-size: clamp(0.75rem, calc(var(--scene-w) * 0.029), 0.94rem);
    --pad-x: 0%;
    --pad-y: 12.5%;
    --span-x: 1;
    --span-y: 0.75;
    --art-w: 768;
    --art-h: 1152;
    aspect-ratio: 768 / 1536;
  }
  @supports (height: 100svh) {
    .room-scene { --scene-w: min(100vw, calc(100svh * 768 / 1536)); }
  }

  /* A label that fits beside a book on a laptop is wider than a phone at this
     scale, so on the tall plate they wrap instead of running off the room. */
  .tag {
    white-space: normal;
    max-width: calc(var(--scene-w) * .44);
    line-height: 1.28;
    text-wrap: balance;
  }

  .thing {
    left: calc(var(--pad-x) + var(--tx) * var(--span-x));
    bottom: calc(var(--pad-y) + var(--tb) * var(--span-y));
    width: calc(var(--tw) * var(--span-x));
  }
  .thing-area { height: calc(var(--th) * var(--span-y)); }

  /* The door stands hard against the right edge of the upright room, so a sign
     centred on it runs off the page. It moves to the wall beside the door.

     24% down its own hit area rather than halfway, because halfway put the sign
     on the front of whatever stands next to the door. That was the wardrobe and
     it is now the bureau, and a sign reading "Back to Absolv" lying across a
     bureau invites exactly the wrong click. The bureau is shorter than the
     wardrobe was, so there is a band of clear wall above it and the sign goes
     there. No geometry check catches this: the two signs never overlapped, they
     were both simply sitting on the same piece of furniture.

     This is keyed on "edge" rather than on "on", because the bookcase is centred
     on its object too and sits against the LEFT edge here: the same rule sent its
     sign off the other side of the phone. Only the object that is actually
     against an edge asks for this. */
  .thing[data-tag~="edge"] .tag {
    left: auto; top: 24%;
    right: 100%; margin-right: .5em;
    transform: translateY(-50%);
  }

  /* A sign sits near the top of its object, which is where a sign belongs and
     where there is usually wall behind it. In the upright room the bureau
     stands right beside the door, so its sign and the door's arrived at the same
     height and printed through each other. "low" drops it to the bottom of the
     object, which only the upright room needs, because the wide room has a metre
     of wall between the two. */
  .thing[data-tag~="low"] .tag { top: 74%; }
}

@media (prefers-reduced-motion: reduce) {
  .thing-art, .thing-area, .tag { transition: none; }
  .thing:hover .thing-art, .thing:focus-visible .thing-art { transform: none; }
}
