/* ---------------------------------------------------------------------------
   Tokens. The layout is the Unity editor's; the colours come from Sanzo
   Wada's A Dictionary of Color Combinations, built on combination 263:
   Slate Color #34454c, Turquoise Green #b5decc, Pinkish Cinnamon #eeb480
   and Burnt Sienna #ae5224. Light is that set printed on the book's cream
   paper; dark is the same set with slate as the ground. Each token is
   light-dark(light, dark). Play mode re-tints the chrome towards turquoise
   the way the editor's playmode tint does.

   The Scene and Game view keep the Unity editor's own colours in both
   themes, so the one loud part of the page still looks like Unity.
--------------------------------------------------------------------------- */
:root {
  --win: light-dark(#ddd3bc, #141c1f);        /* gaps between docked panels */
  --panel: light-dark(#fbf8f0, #212d32);
  --head: light-dark(#f2ecdd, #293840);       /* component header bars */
  --head-hover: light-dark(#ebe3d0, #34454c);
  --tabbar: light-dark(#e8e0cb, #1a2427);
  --line: light-dark(#d6cbb1, #10171a);
  --field: light-dark(#f6f1e4, #1b262a);
  --field-line: light-dark(#cdc0a2, #3b4e56);
  --scroll: light-dark(#c6b897, #46595f);

  --text: light-dark(#1f2a2e, #ece4cc);
  --text-strong: light-dark(#111314, #fbf5e2);
  --dim: light-dark(#596366, #a6a28e);
  --link: light-dark(#8f421b, #b5decc);
  --focus: light-dark(#005b8d, #78cdd0);       /* Helvetia Blue, Calamine Blue */

  --select: light-dark(#b5decc, #1f5550);     /* selected row */
  --on-select: light-dark(#1f2a2e, #f5ecc2);
  --hover: light-dark(#efe7d5, #2b3a40);
  --active: light-dark(#ae5224, #eeb480);     /* focused tab, pressed play, the main action */
  --active-hover: light-dark(#933f17, #f5c89f);
  --on-active: light-dark(#fbf8f0, #1f2a2e);
  --btn: light-dark(#e6dcc4, #34454c);
  --btn-hover: light-dark(#dacfb3, #41565e);
  --btn-text: light-dark(#1f2a2e, #ece4cc);
  --btn-text-off: light-dark(#a49a83, #75847f);

  --clip: light-dark(#b5decc, #3d6563);       /* a job on the timeline */
  --clip-edge: light-dark(#34454c, #b5decc);
  --on-clip: light-dark(#1f2a2e, #f5ecc2);

  /* Scene and Game view: Unity's colours, the same in both themes. */
  --outline: #ff6a00;    /* selection outline in the scene */
  --axis-x: #e5533a;
  --axis-y: #93d34b;
  --axis-z: #4a86f7;
  --hot: #f5e04a;        /* hovered gizmo handle, skill tokens */

  --sky-top: #22303f;
  --sky-low: #5f7386;
  --ground-far: #4a4947;
  --ground-near: #343332;

  --toolbar-h: 3rem;
  --nav-h: 0rem;         /* the contents strip, on screens too narrow for the side panel */
  --gap: 2px;
  --pad: 1.25rem;

  --wide: 125%;
  color-scheme: light dark;
}
/* The theme button pins one scheme; otherwise the system setting decides. */
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

body[data-mode="play"] {
  --win: light-dark(#cdd8cd, #0f181a);
  --panel: light-dark(#f1f6ef, #1b2b2d);
  --head: light-dark(#e5eee4, #223537);
  --head-hover: light-dark(#dbe6da, #2c4345);
  --tabbar: light-dark(#dce6db, #152123);
  --line: light-dark(#c2cfc2, #0b1314);
  --field: light-dark(#eaf2e8, #172426);
  --field-line: light-dark(#b5c5b6, #34504f);
}

/* ---------------------------------------------------------------------------
   Base
--------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--toolbar-h) + var(--nav-h) + 0.75rem);
  -webkit-text-size-adjust: 100%;
  /* The page only ever scrolls up and down; the timeline and the contents
     strip scroll sideways inside their own boxes. Clip rather than hide, so
     the pinned toolbar and panels keep working. */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--win);
  color: var(--text);
  font: 400 1rem/1.6 "Archivo", system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  transition: background-color 0.25s;
}

[hidden] { display: none !important; }
.print-only { display: none; }

h1, h2, h3, p, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }

a { color: var(--link); text-underline-offset: 0.18em; }
a:hover { color: var(--text-strong); }

button { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: fixed;
  left: 0.5rem;
  top: -4rem;
  z-index: 30;
  padding: 0.5rem 0.75rem;
  background: var(--active);
  color: var(--on-active);
  border-radius: 3px;
}
.skip-link:focus { top: 0.5rem; }

/* ---------------------------------------------------------------------------
   Toolbar
--------------------------------------------------------------------------- */
.toolbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.75rem;
  height: var(--toolbar-h);
  padding: 0 0.75rem;
  background: var(--panel);
  border-bottom: var(--gap) solid var(--win);
  transition: background-color 0.25s;
}

.toolbar__id {
  justify-self: start;
  color: var(--text);
  font-weight: 650;
  font-stretch: 112%;
  text-decoration: none;
  white-space: nowrap;
}

.toolbar__role {
  margin-left: 0.5rem;
  color: var(--dim);
  font-weight: 400;
  font-stretch: 100%;
  font-size: 0.875rem;
}

.toolbar__end {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.theme-toggle {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 1.75rem;
  padding: 0;
  background: transparent;
  border: 1px solid var(--field-line);
  border-radius: 3px;
  color: var(--dim);
  cursor: pointer;
}
.theme-toggle:hover { background: var(--hover); color: var(--text-strong); }
.theme-toggle svg { width: 0.95rem; height: 0.95rem; fill: currentColor; }
.theme-toggle .icon-sun,
.theme-toggle[aria-pressed="true"] .icon-moon { display: none; }
.theme-toggle[aria-pressed="true"] .icon-sun { display: block; }

.toolbar__cta {
  padding: 0.3rem 0.8rem;
  background: var(--active);
  border-radius: 3px;
  color: var(--on-active);
  font-size: 0.875rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.toolbar__cta:hover { background: var(--active-hover); }

.transport {
  display: flex;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 4px;
  overflow: hidden;
}

.transport__btn {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 1.75rem;
  padding: 0;
  background: var(--btn);
  color: var(--btn-text);
  border: 0;
  cursor: pointer;
}
.transport__btn svg { width: 1rem; height: 1rem; fill: currentColor; }
.transport__btn:hover:not(:disabled) { background: var(--btn-hover); }
.transport__btn:disabled { cursor: default; }
.transport__btn:disabled { color: var(--btn-text-off); }
.transport__btn[aria-pressed="true"] { background: var(--active); color: var(--on-active); }
.transport__btn:focus-visible { outline-offset: -2px; }

/* The one control a visitor needs is spelled out; Pause and Step only
   appear once a game is running. */
.transport__btn--play {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: auto;
  padding: 0 0.75rem 0 0.6rem;
  font-size: 0.875rem;
  font-weight: 600;
  white-space: nowrap;
}
body[data-mode="play"] .transport__btn--play { background: var(--active); color: var(--on-active); }
body[data-mode="edit"] .transport__btn:not(.transport__btn--play) { display: none; }

.icon-stop { display: none; }
body[data-mode="play"] .icon-play { display: none; }
body[data-mode="play"] .icon-stop { display: block; }

/* ---------------------------------------------------------------------------
   Docked layout
--------------------------------------------------------------------------- */
.editor {
  display: grid;
  grid-template-columns: 13.5rem minmax(0, 1fr) 20.5rem;
  gap: var(--gap);
  align-items: start;
  max-width: 90rem;
  margin: 0 auto;
}

.workspace {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--gap);
  min-width: 0;
}

.panel {
  background: var(--panel);
  transition: background-color 0.25s;
}

.hierarchy,
.inspector {
  position: sticky;
  top: calc(var(--toolbar-h) + var(--nav-h) + var(--gap));
  max-height: calc(100vh - var(--toolbar-h) - var(--nav-h) - var(--gap));
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--scroll) transparent;
}
.hierarchy { min-height: calc(100vh - var(--toolbar-h) - var(--gap)); }

/* Panel tabs name the panel, the way dock tabs do in the editor. */
.panel__tabs {
  display: flex;
  background: var(--tabbar);
}

.panel__tab {
  display: block;
  width: fit-content;
  padding: 0.3rem 0.85rem 0.35rem;
  background: var(--panel);
  border: 0;
  border-top: 2px solid var(--active);
  box-shadow: 100vw 0 0 100vw var(--tabbar);
  clip-path: inset(0 -100vw 0 0);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.5;
}
.panel { overflow: clip; }

/* The two side panels are pinned to the window, so when their content is
   taller than it they scroll on their own, with their tab staying on top. */
.panel.hierarchy,
.panel.inspector { overflow: hidden auto; }
.hierarchy > .panel__tab,
.inspector > .panel__tab {
  position: sticky;
  top: 0;
  z-index: 1;
}

.panel__tab--btn {
  box-shadow: none;
  clip-path: none;
  background: transparent;
  border-top-color: transparent;
  color: var(--dim);
  cursor: pointer;
}
.panel__tab--btn:hover { color: var(--text); }
.panel__tab--btn[aria-pressed="true"] {
  background: var(--panel);
  border-top-color: var(--active);
  color: var(--text);
}
.panel__tab--btn:focus-visible { outline-offset: -2px; }

/* ---------------------------------------------------------------------------
   Hierarchy
--------------------------------------------------------------------------- */
.tree { padding: 0.4rem 0; font-size: 0.8125rem; }
.tree ul { --depth: 1; }
.tree ul ul { --depth: 2; }
.tree ul ul ul { --depth: 3; }

.tree__row {
  position: relative;
  display: block;
  padding: 0.2rem 0.75rem 0.2rem calc(1.6rem + var(--depth, 0) * 0.9rem);
  color: var(--text);
  text-decoration: none;
  line-height: 1.55;
}
.tree__row:hover { background: var(--hover); color: var(--text-strong); }
.tree__row[aria-current="true"] { background: var(--select); color: var(--on-select); }
.tree__row:focus-visible { outline-offset: -2px; }

.tree__row--parent::before {
  content: "";
  position: absolute;
  left: calc(0.75rem + var(--depth, 0) * 0.9rem);
  top: 0.72rem;
  border: 0.28rem solid transparent;
  border-top-color: var(--dim);
  border-bottom-width: 0;
}

/* ---------------------------------------------------------------------------
   Scene view. This is the one loud part of the page.
--------------------------------------------------------------------------- */
.viewport {
  position: relative;
  height: clamp(17rem, 44vh, 26rem);
  overflow: hidden;
  /* Safari can let the tilted floor grid escape overflow: hidden and widen
     the page; paint containment clips it for certain. */
  contain: paint;
  container-type: inline-size;
  background:
    linear-gradient(
      var(--sky-top) 0%,
      var(--sky-low) 66%,
      var(--ground-far) 66%,
      var(--ground-near) 100%
    );
}

.viewport__grid {
  position: absolute;
  left: -60%;
  right: -60%;
  top: 66%;
  height: 80%;
  background-image:
    linear-gradient(to right, rgb(255 255 255 / 0.2) 1px, transparent 1px),
    linear-gradient(to bottom, rgb(255 255 255 / 0.2) 1px, transparent 1px);
  background-size: 3.5rem 3.5rem;
  background-position: center top;
  transform: perspective(16rem) rotateX(62deg);
  transform-origin: 50% 0;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 45%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 45%);
}

.object {
  position: absolute;
  left: 50%;
  top: 40%;
  font-size: clamp(2.5rem, 12.5cqi, 6.75rem);
  transform: translate(
    calc(-50% + var(--x, 0px) + var(--shake-x, 0px)),
    calc(-50% + var(--y, 0px) + var(--shake-y, 0px))
  );
}

.object__title { font-size: inherit; }

.object__name {
  display: block;
  color: #ededed;
  font-weight: 800;
  font-stretch: var(--wide);
  line-height: 1;
  letter-spacing: -0.01em;
  white-space: nowrap;
  -webkit-text-stroke: 0.045em var(--outline);
  paint-order: stroke fill;
  user-select: none;
}

.object__letter { display: inline-block; transform-origin: 50% 82%; will-change: transform; }
/* Each letter can be dragged on its own to lay out a level. */
body[data-mode="edit"] .object__letter { cursor: grab; }
body[data-mode="edit"] .object__letter.is-dragging { cursor: grabbing; -webkit-text-stroke-color: var(--hot); }
@media (hover: hover) {
  body[data-mode="edit"] .object__letter:hover { -webkit-text-stroke-color: var(--hot); }
}
.object__gap { display: inline-block; width: 0.3em; }
.object__name.is-returning .object__letter { transition: transform 0.35s cubic-bezier(0.2, 0.8, 0.2, 1); }

/* The pivot sits under the word space, so the Y arrow rises between the two
   words and the X arrow runs beneath the baseline; neither covers a letter.
   Sizes are in em so the gizmo scales with the name. */
.gizmo {
  position: absolute;
  left: var(--pivot, 46%);
  top: 0.98em;
  width: 0;
  height: 0;
}

.gizmo__handle {
  position: absolute;
  padding: 0;
  background: none;
  border: 0;
  touch-action: none;
  cursor: grab;
}
.gizmo__handle:active { cursor: grabbing; }
.gizmo__handle svg { display: block; width: 100%; height: 100%; fill: currentColor; }
.gizmo__handle:hover,
.gizmo__handle.is-dragging { color: var(--hot); }

.gizmo__handle--x { left: 0; top: -0.75rem; width: 0.85em; height: 1.5rem; color: var(--axis-x); }
.gizmo__handle--y { left: -0.75rem; bottom: 0; width: 1.5rem; height: 1.12em; color: var(--axis-y); }
.gizmo__handle--free {
  left: -0.75rem;
  top: -0.75rem;
  width: 1.5rem;
  height: 1.5rem;
  color: var(--axis-z);
}
.gizmo__handle--free::before {
  content: "";
  position: absolute;
  inset: calc(50% - max(0.3rem, 0.07em));
  background: currentColor;
  border: 1px solid #fff;
}

/* Where the name has been dragged to. Only shown once it has moved, so
   visitors who never touch the arrows never see it. */
.readout {
  position: absolute;
  left: 0.6rem;
  bottom: 0.6rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.4rem 0.3rem 0.6rem;
  background: color-mix(in srgb, var(--panel) 90%, transparent);
  border: 1px solid var(--line);
  border-radius: 3px;
  font-size: 0.8125rem;
}
.readout__label { color: var(--dim); }
.readout__axis { display: flex; align-items: center; gap: 0.3rem; font-weight: 600; }
.readout__axis--x { color: var(--axis-x); }
.readout__axis--y { color: var(--axis-y); }
.readout__axis output {
  min-width: 3rem;
  padding: 0.05rem 0.4rem;
  background: var(--field);
  border: 1px solid var(--field-line);
  border-radius: 3px;
  color: var(--text);
  font-weight: 400;
}
.readout__reset {
  padding: 0.05rem 0.5rem;
  background: var(--btn);
  color: var(--btn-text);
  border: 1px solid var(--line);
  border-radius: 3px;
  cursor: pointer;
}
.readout__reset:hover { background: var(--btn-hover); }

/* Game view: no editor overlays, the camera just sees the object. */
body[data-mode="play"] .viewport__grid,
body[data-mode="play"] .readout,
body[data-mode="play"] .gizmo { display: none; }
body[data-mode="play"] .object__name {
  -webkit-text-stroke-width: 0;
  cursor: default;
}

/* ---------------------------------------------------------------------------
   Skill collector: what runs in the Game view. script.js sizes and moves
   the cube and tokens; everything sits on the ground line at --ground.
--------------------------------------------------------------------------- */
.viewport:focus-visible { outline-offset: -2px; }

.game {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transform: translate(var(--shake-x, 0px), var(--shake-y, 0px));
}

/* Dust, bursts, confetti and the cube's trail are drawn here. */
.game__fx {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.game__hud {
  position: absolute;
  left: 0.85rem;
  top: 0.6rem;
  display: flex;
  gap: 0.9rem;
  color: #fff;
  font-size: 0.875rem;
  font-weight: 600;
  text-shadow: 0 1px 2px rgb(0 0 0 / 0.6);
}
.game__count { transform-origin: left center; }
.game__count.is-bumped { animation: bump 0.25s ease-out; }
@keyframes bump {
  30% { scale: 1.25; color: var(--hot); }
}
.game__clock { font-weight: 400; }

.game__sound {
  position: absolute;
  right: 0.6rem;
  top: 0.45rem;
  padding: 0.15rem 0.55rem;
  background: rgb(20 20 20 / 0.55);
  border: 1px solid rgb(255 255 255 / 0.25);
  border-radius: 3px;
  color: #fff;
  font-size: 0.8125rem;
  cursor: pointer;
  pointer-events: auto;
}
.game__sound:hover { background: rgb(20 20 20 / 0.8); }
.game__sound[data-on="true"] { border-color: var(--hot); }

.cube,
.token {
  position: absolute;
  left: 0;
  bottom: var(--ground);
}

/* Unity's default cube: a front face plus a sliver of top and side. */
.cube {
  background: #cfcfcf;
  filter: drop-shadow(0 0 1px rgb(0 0 0 / 0.7));
  transform-origin: 50% 100%;
  will-change: transform;
}
.cube::before,
.cube::after { content: ""; position: absolute; }
.cube::before {
  left: 0;
  bottom: 100%;
  width: 100%;
  height: 30%;
  background: #f2f2f2;
  transform: skewX(-45deg);
  transform-origin: bottom left;
}
.cube::after {
  left: 100%;
  top: 0;
  width: 30%;
  height: 100%;
  background: #999;
  transform: skewY(-45deg);
  transform-origin: top left;
}

/* The best run so far, replayed alongside as something to race. */
.cube--ghost { opacity: 0.3; filter: none; }

.token {
  background: var(--hot);
  box-shadow: 0 0 0 1px #5c5200, 0 0 0.6rem rgb(245 224 74 / 0.45);
  animation: token-in 0.35s cubic-bezier(0.3, 1.6, 0.5, 1) backwards;
  will-change: transform;
}
@keyframes token-in {
  from { scale: 0; }
}

/* At the finish each token flies from the cube to its skill in the sidebar. */
.flyer {
  position: fixed;
  left: -0.4rem;
  top: -0.4rem;
  z-index: 40;
  width: 0.8rem;
  height: 0.8rem;
  background: var(--hot);
  box-shadow: 0 0 0 1px #5c5200, 0 0 0.6rem rgb(245 224 74 / 0.6);
  pointer-events: none;
}
.chips li.is-banked { animation: banked 0.45s ease-out; }
@keyframes banked {
  30% { scale: 1.18; background: var(--hot); color: #1a1a1a; }
}

/* Goal and controls, shown until the player first moves. */
.game__hint {
  position: absolute;
  left: 50%;
  top: 2.6rem;
  width: max-content;
  max-width: calc(100% - 1.5rem);
  padding: 0.5rem 0.9rem 0.6rem;
  background: rgb(20 20 20 / 0.72);
  border-radius: 4px;
  color: #fff;
  text-align: center;
  transform: translateX(-50%);
  transition: opacity 0.3s;
}
.game__hint.is-gone { opacity: 0; }
.game__hint-goal { font-weight: 650; font-stretch: 112%; }
.game__hint-keys,
.game__hint-touch { font-size: 0.875rem; }
.game__hint-touch,
body.uses-touch .game__hint-keys { display: none; }
body.uses-touch .game__hint-touch { display: block; }
.game__hint kbd {
  display: inline-block;
  min-width: 1.5rem;
  margin-left: 0.35rem;
  padding: 0 0.35rem;
  background: #f0f0f0;
  border-radius: 3px;
  box-shadow: 0 2px 0 #9a9a9a;
  color: #1a1a1a;
  font: inherit;
  font-weight: 600;
  line-height: 1.4;
}
.game__hint kbd:first-child { margin-left: 0; }

.game__win {
  position: absolute;
  left: 50%;
  top: 1.25rem;
  width: max-content;
  max-width: calc(100% - 2rem);
  padding: 0.9rem 1.1rem 1rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-top: 2px solid var(--active);
  transform: translateX(-50%);
  pointer-events: auto;
  animation: win-in 0.3s cubic-bezier(0.3, 1.5, 0.5, 1) backwards;
}
@keyframes win-in {
  from { opacity: 0; scale: 0.85; }
}
.game__win-title {
  font-size: 1.25rem;
  font-weight: 650;
  font-stretch: 112%;
  line-height: 1.3;
}
.game__win-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }

.button {
  padding: 0.3rem 0.8rem;
  background: var(--btn);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--btn-text);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.6;
  text-decoration: none;
  cursor: pointer;
}
.button:hover { background: var(--btn-hover); color: var(--btn-text); }
.button--primary { background: var(--active); border-color: var(--active); color: var(--on-active); }
.button--primary:hover { background: var(--active-hover); border-color: var(--active-hover); color: var(--on-active); }

/* On-screen controls, shown only in play mode on touch devices. */
.touchpad {
  display: none;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.5rem 0.85rem;
  border-top: 1px solid var(--line);
}
body[data-mode="play"].uses-touch .touchpad { display: flex; }
.touchpad__move { display: flex; gap: 0.5rem; }
.touchpad__btn {
  display: grid;
  place-items: center;
  min-width: 3.75rem;
  height: 3rem;
  padding: 0 1rem;
  background: var(--btn);
  border: 1px solid var(--line);
  border-radius: 4px;
  color: var(--btn-text);
  font-weight: 600;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.touchpad__btn svg { width: 1.25rem; height: 1.25rem; fill: currentColor; }
.touchpad__btn.is-held { background: var(--active); color: var(--on-active); }

/* While playing, the sidebar's skills read as a checklist. */
#skills .chips li { transition: opacity 0.2s, border-color 0.2s; }
body[data-mode="play"] #skills .chips li { opacity: 0.45; }
body[data-mode="play"] #skills .chips li.is-collected {
  opacity: 1;
  border-color: var(--hot);
  animation: chip-lit 0.5s ease-out;
}
@keyframes chip-lit {
  from { background: var(--hot); color: #1a1a1a; }
}

.statusbar {
  padding: 0.3rem 0.85rem;
  border-top: 1px solid var(--line);
  font-size: 0.875rem;
}

/* ---------------------------------------------------------------------------
   Profile
--------------------------------------------------------------------------- */
.profile {
  display: grid;
  grid-template-columns: 9rem minmax(0, 1fr);
  gap: var(--pad);
  align-items: start;
  padding: var(--pad);
}

.portrait {
  position: relative;
  aspect-ratio: 1;
  background: var(--field);
  border: 1px solid var(--field-line);
  border-radius: 3px;
  overflow: hidden;
}
.portrait img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.portrait__mono {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--dim);
  font-size: 2rem;
  font-weight: 800;
  font-stretch: var(--wide);
}
/* The script removes the photo if it fails to load, which brings the monogram back. */
.portrait img ~ .portrait__mono { display: none; }

.profile__title {
  margin-bottom: 0.4rem;
  font-size: 1.75rem;
  font-weight: 650;
  font-stretch: 112%;
  line-height: 1.2;
}
.profile__text { max-width: 38rem; }
.actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.9rem; }

/* ---------------------------------------------------------------------------
   Timeline: one clip per employer, width proportional to time there.
   Positions are months counted from January 2012, over a 180-month ruler.
--------------------------------------------------------------------------- */
.timeline {
  --months: 180;
  padding: 0.9rem var(--pad) 1.1rem;
}

/* Each year gets a fixed, roomy width, so the strip is wider than the panel
   and scrolls sideways (drag it, swipe it, or use the scrollbar). It fades at
   whichever edge has more to see. */
.timeline__scroll {
  --fade-left: 0rem;
  --fade-right: 0rem;
  overflow-x: auto;
  cursor: grab;
  user-select: none;
  padding-bottom: 0.35rem;
  scrollbar-width: thin;
  scrollbar-color: var(--scroll) transparent;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--fade-left), #000 calc(100% - var(--fade-right)), transparent);
          mask-image: linear-gradient(to right, transparent, #000 var(--fade-left), #000 calc(100% - var(--fade-right)), transparent);
}
.timeline__scroll.more-left { --fade-left: 2.5rem; }
.timeline__scroll.more-right { --fade-right: 2.5rem; }
.timeline__scroll:focus-visible { outline-offset: -2px; }
.timeline__scroll.is-panning,
.timeline__scroll.is-panning .clip { cursor: grabbing; }
.timeline__inner { min-width: calc(15 * clamp(6rem, 7vw, 6.5rem)); }

.timeline__ruler {
  display: grid;
  grid-template-columns: repeat(15, minmax(0, 1fr));
  color: var(--dim);
  font-size: 0.75rem;
  line-height: 1.4;
}
.timeline__ruler li {
  padding: 0 0 0.3rem 0.25rem;
  border-left: 1px solid var(--field-line);
}

/* Company marks: the real logo on a white tile where there is one, a
   lettered tile where there isn't. */
.logo {
  --logo: 2rem;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--logo);
  min-width: var(--logo);
  padding: 0 0.15rem;
  background: #fff;
  border-radius: 3px;
  overflow: hidden;
}
.logo img {
  display: block;
  width: auto;
  max-width: calc(var(--logo) * 2.4);
  height: calc(var(--logo) - 0.3rem);
  object-fit: contain;
}
.logo--letter {
  background: var(--field);
  border: 1px solid var(--field-line);
  color: var(--dim);
  font-size: 0.9375rem;
  font-weight: 800;
  font-stretch: var(--wide);
  line-height: 1;
}

.timeline__track {
  position: relative;
  height: 2.5rem;
  background: var(--field);
  border: 1px solid var(--line);
}

.clip {
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: calc(var(--from) / var(--months) * 100%);
  width: calc((var(--to) - var(--from)) / var(--months) * 100%);
  display: flex;
  align-items: center;
  min-width: 0;
  padding: 0 0.4rem 0 0.2rem;
  overflow: clip;
  background: var(--clip);
  border-left: 2px solid var(--clip-edge);
  color: var(--on-clip);
  font-size: 0.8125rem;
  text-decoration: none;
}
.clip { container-type: inline-size; }
/* A long bar's logo and name slide along with the scroll, so a bar that
   starts off screen still says whose it is. The offset clears the edge fade. */
.clip__label {
  position: sticky;
  left: 2.6rem;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}
.clip .logo { --logo: 1.75rem; }
.clip .logo img { max-width: 2.4rem; }
.clip__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A clip too short to hold a readable label keeps just its logo, and one too
   short for that goes bare; its link still names it. */
@container (max-width: 7rem) {
  .clip__name { display: none; }
}
@container (max-width: 1.7rem) {
  .clip .logo { display: none; }
}
.clip:hover { background: var(--active); color: var(--on-active); }
.clip:focus-visible { outline-offset: 1px; z-index: 1; }

.clip--angry-mob    { --from: 5;     --to: 19; }
.clip--idea-studios { --from: 19;    --to: 36; }
.clip--creative-web { --from: 36;    --to: 38; }
.clip--transylgamia { --from: 38;    --to: 52; }
.clip--bull         { --from: 53;    --to: 63; }
.clip--avangarde    { --from: 63;    --to: 91.5; }
.clip--firebyte     { --from: 91.5;  --to: 143; }
/* Current role: runs off the end of the ruler. */
.clip--netflix {
  --from: 145;
  --to: 180;
  background: linear-gradient(to right, var(--clip) 55%, transparent);
}
.clip--netflix:hover { background: linear-gradient(to right, var(--active) 55%, transparent); }

/* ---------------------------------------------------------------------------
   Components: foldouts used for each job and each Inspector block.
--------------------------------------------------------------------------- */
.component { border-top: 1px solid var(--line); }

.component__head {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.4rem var(--pad) 0.4rem 2rem;
  background: var(--head);
  cursor: pointer;
  list-style: none;
  transition: background-color 0.25s;
}
.component__head::-webkit-details-marker { display: none; }
.component__head::before {
  content: "";
  position: absolute;
  left: 0.9rem;
  top: 50%;
  border: 0.3rem solid transparent;
  border-left-color: var(--dim);
  border-right-width: 0;
  transform: translateY(-50%);
  transition: transform 0.15s;
}
.component[open] > .component__head::before { transform: translateY(-50%) rotate(90deg); }
.component__head:hover { background: var(--head-hover); }
.component__head:focus-visible { outline-offset: -2px; }
.component:target > .component__head,
.component.is-found > .component__head { background: var(--select); color: var(--on-select); }
.component:target > .component__head .job__dates { color: var(--on-select); }

.component__title { font-size: 0.875rem; font-weight: 600; line-height: 1.5; }
.component__body { padding: 0.85rem var(--pad) 1.1rem; }

/* Jobs */
.job .component__head { flex-wrap: wrap; align-items: center; row-gap: 0; }
.job__company {
  font-size: 1.25rem;
  font-weight: 650;
  font-stretch: 112%;
  line-height: 1.4;
}
.job__dates { margin-left: auto; color: var(--dim); font-size: 0.875rem; white-space: nowrap; }
.job .component__body { padding-left: 2rem; max-width: 46rem; }
.job__role { font-weight: 600; }
.job__place { color: var(--dim); font-weight: 400; }
.job__about { margin-top: 0.35rem; color: var(--dim); }

.job__links { margin-top: 0.6rem; }
.job__list { margin-top: 0.6rem; }
.job__list li {
  position: relative;
  padding-left: 1.1rem;
}
.job__list li + li { margin-top: 0.35rem; }
.job__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 0.4rem;
  height: 0.4rem;
  background: var(--dim);
}

/* ---------------------------------------------------------------------------
   Projects: name and client on the left, what it was and what Alex built
   on the right.
--------------------------------------------------------------------------- */
.project {
  display: grid;
  grid-template-columns: 13rem minmax(0, 1fr);
  gap: 0.25rem 1.5rem;
  padding: 0.9rem var(--pad) 1rem;
  border-top: 1px solid var(--line);
}
.project:target { background: var(--head); }
.project__name { font-size: 1.0625rem; font-weight: 650; font-stretch: 112%; line-height: 1.35; }
.project__for { color: var(--dim); font-size: 0.875rem; }
.project__body { max-width: 40rem; }
.project .chips { margin-top: 0.5rem; font-size: 0.8125rem; }

/* A video's own thumbnail, which swaps for the player when clicked. Nothing
   from YouTube but that thumbnail loads until then. */
.trailer {
  position: relative;
  display: block;
  max-width: 22rem;
  margin-top: 0.6rem;
  aspect-ratio: 16 / 9;
  background: #000;
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
}
.trailer img { display: block; width: 100%; height: 100%; object-fit: cover; }
.trailer__label {
  position: absolute;
  left: 0.4rem;
  bottom: 0.4rem;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.2rem 0.55rem 0.2rem 0.5rem;
  background: rgb(20 20 20 / 0.88);
  border-radius: 3px;
  color: #fff;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.5;
}
.trailer__label::before {
  content: "";
  border: 0.32rem solid transparent;
  border-left: 0.5rem solid currentColor;
  border-right-width: 0;
}
.trailer:hover .trailer__label { background: var(--active); color: var(--on-active); }

/* Screenshots: one large, then a row of two smaller. Clicking opens it full size. */
.shot {
  display: block;
  max-width: 22rem;
  margin-top: 0.6rem;
  aspect-ratio: 16 / 9;
  background: #000;
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
  cursor: zoom-in;
}
.shot img { display: block; width: 100%; height: 100%; object-fit: cover; }
.shot:hover { border-color: var(--active); }

.project__more {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.4rem;
  max-width: 22rem;
  margin-top: 0.4rem;
}
.project__more .shot,
.project__more .trailer { margin-top: 0; }
/* In the small row a video shows just its play mark; its link is still named. */
.trailer--small .trailer__label { padding: 0.3rem 0.4rem 0.3rem 0.5rem; font-size: 0; gap: 0; }

.lightbox {
  max-width: min(96vw, 90rem);
  max-height: 94vh;
  padding: 0;
  background: #000;
  border: 1px solid var(--field-line);
  color: #fff;
  overflow: hidden;
}
.lightbox::backdrop { background: rgb(0 0 0 / 0.8); }
.lightbox img { display: block; max-width: 100%; max-height: calc(94vh - 2.6rem); margin: 0 auto; }
.lightbox__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.4rem 0.5rem 0.4rem 0.75rem;
  background: var(--panel);
  font-size: 0.875rem;
}
.trailer__credit { margin-top: 0.25rem; color: var(--dim); font-size: 0.75rem; }
.project__player {
  grid-column: 1 / -1;
  width: 100%;
  max-width: 48rem;
  margin-top: 0.6rem;
  aspect-ratio: 16 / 9;
  border: 0;
}

/* ---------------------------------------------------------------------------
   Inspector
--------------------------------------------------------------------------- */
.inspector { font-size: 0.875rem; }
.inspector .component__head { padding-left: 1.9rem; padding-right: 0.85rem; }
.inspector .component__head::before { left: 0.85rem; }
.inspector .component__body { padding: 0.7rem 0.85rem 0.95rem; }

.props { display: grid; gap: 0.35rem; }
.props--header { padding: 0.8rem 0.85rem 0.95rem; }

.prop {
  display: grid;
  grid-template-columns: 5.25rem minmax(0, 1fr);
  gap: 0.5rem;
  align-items: baseline;
}
.prop dt { color: var(--dim); }
.prop dd {
  padding: 0.15rem 0.5rem;
  background: var(--field);
  border: 1px solid var(--field-line);
  border-radius: 3px;
  overflow-wrap: anywhere;
}

.note { color: var(--dim); }

.group {
  margin: 0.8rem 0 0.4rem;
  color: var(--dim);
  font-size: inherit;
  font-weight: 400;
}
.group:first-child { margin-top: 0; }

.chips { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.chips li {
  padding: 0.15rem 0.5rem;
  background: var(--field);
  border: 1px solid var(--field-line);
  border-radius: 3px;
}

/* ---------------------------------------------------------------------------
   Back to top: a small editor button that turns up once the Scene view has
   scrolled away. Only on screens without the Contents panel.
--------------------------------------------------------------------------- */
.to-top {
  position: fixed;
  right: 1rem;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  z-index: 25;
  display: none;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  background: var(--btn);
  border: 1px solid var(--line);
  border-radius: 4px;
  box-shadow: 0 4px 12px light-dark(rgb(52 69 76 / 0.25), rgb(0 0 0 / 0.45));
  color: var(--btn-text);
  opacity: 0;
  visibility: hidden;
  translate: 0 0.75rem;
  transition: opacity 0.2s, translate 0.2s, visibility 0.2s;
}
.to-top svg { width: 1.1rem; height: 1.1rem; fill: currentColor; }
.to-top:hover { background: var(--btn-hover); color: var(--text-strong); }
.to-top.is-shown { opacity: 1; visibility: visible; translate: 0 0; }

/* ---------------------------------------------------------------------------
   Narrower screens
--------------------------------------------------------------------------- */
@media (max-width: 73rem) {
  :root { --nav-h: 2.75rem; }
  .editor { grid-template-columns: minmax(0, 1fr) 20.5rem; }
  .to-top { display: grid; }
  /* The strip docks straight onto the toolbar, with no seam between them. */
  .toolbar { border-bottom: 0; }

  /* Contents turns into a strip of dock tabs pinned under the toolbar, one
     per section; the companies under Experience fold into that one tab. */
  /* The toolbar and the strip are pinned separately, and phones can round
     their positions apart mid-scroll, opening a hairline the page shows
     through. So the strip starts 2px up, tucked under the toolbar. */
  .panel.hierarchy {
    grid-column: 1 / -1;
    top: calc(var(--toolbar-h) - 2px);
    margin-top: -2px;
    padding-top: 2px;
    z-index: 15;
    min-height: 0;
    max-height: none;
    overflow: clip;
    background: var(--tabbar);
  }
  .hierarchy > .panel__tab,
  .tree > li > .tree__row,
  .tree ul ul { display: none; }
  .tree { padding: 0; font-size: 0.875rem; }
  .tree > li > ul {
    display: flex;
    height: var(--nav-h);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }
  .tree > li > ul::-webkit-scrollbar { display: none; }
  .tree > li > ul > li { flex: none; }
  .tree > li > ul > li > .tree__row {
    display: flex;
    align-items: center;
    height: 100%;
    padding: 0 1rem;
    border-top: 2px solid transparent;
    color: var(--dim);
    white-space: nowrap;
  }
  .tree__row--parent::before { display: none; }
  .tree > li > ul > li > .tree__row:hover { background: none; color: var(--text); }
  .tree > li > ul > li > .tree__row[aria-current="true"],
  .tree > li > ul > li:has(ul [aria-current="true"]) > .tree__row {
    background: var(--panel);
    border-top-color: var(--active);
    color: var(--text);
  }
}

@media (max-width: 54rem) {
  :root { --pad: 1rem; }
  .editor { grid-template-columns: minmax(0, 1fr); }
  .inspector { position: static; max-height: none; font-size: 0.9375rem; }
  .toolbar__role { display: none; }
  .viewport { height: clamp(15rem, 40vh, 20rem); }
  .profile { grid-template-columns: 6.5rem minmax(0, 1fr); }
  .profile__title { font-size: 1.4rem; }
  .job .component__body { padding-left: var(--pad); }
  .project { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 36rem) {
  .statusbar { padding: 0.5rem var(--pad); text-align: center; }

  /* Profile as a centred card: photo, title, summary, then the actions with
     Email Alex as the full-width first choice. */
  .profile {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    gap: 0.9rem;
    padding: 1.5rem var(--pad) 1.6rem;
    text-align: center;
  }
  .portrait { width: 8.5rem; }
  .profile__title { font-size: 1.6rem; }
  .actions { justify-content: center; margin-top: 1.1rem; }
  .actions .button { flex: 1 1 auto; padding: 0.55rem 0.9rem; text-align: center; }
  .actions .button--primary { flex-basis: 100%; }

  /* Job headers: logo beside the name, dates tucked under it rather than
     stranded on a line of their own. */
  .job .component__head {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 0.75rem;
    padding-top: 0.6rem;
    padding-bottom: 0.6rem;
  }
  .job .component__head .logo { grid-row: span 2; }
  .job__company { font-size: 1.15rem; line-height: 1.25; }
  .job__dates { grid-column: 2; margin-left: 0; }

  /* Pictures and videos use the full width of the phone. */
  .trailer,
  .shot,
  .project__more { max-width: none; }
}

@media (max-width: 30rem) {
  /* No room for Pause and Step beside the name and the email button. */
  .transport__btn:not(.transport__btn--play) { display: none; }
}

/* ---------------------------------------------------------------------------
   Motion and print
--------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

@media print {
  :root {
    --win: #fff; --panel: #fff; --head: #fff; --tabbar: #fff; --field: #fff;
    --line: #bbb; --field-line: #bbb; --text: #000; --dim: #444; --link: #000;
    color-scheme: light;
  }
  :root[data-theme] { color-scheme: light; }
  body { font-size: 10.5pt; }
  .toolbar, .hierarchy, .panel__tabs, .viewport__grid, .gizmo, .statusbar,
  .readout, .actions, .timeline, .portrait__mono, .skip-link, .game, .touchpad,
  .trailer, .trailer__credit, .project__player, .logo--letter, .shot, .project__more, .lightbox, .to-top { display: none !important; }
  .logo { border: 1px solid #bbb; margin-right: 0.5rem; }
  .editor { display: block; }
  .inspector { position: static; max-height: none; }
  .viewport { height: auto; background: none; }
  .object { position: static; transform: none; }
  .object__name { color: #000; font-size: 28pt; -webkit-text-stroke-width: 0; }
  .object__letter { transform: none !important; }
  .panel__tab { border: 0; box-shadow: none; clip-path: none; padding-left: 0; font-size: 12pt; font-weight: 700; }
  .component__head, .inspector .component__head { padding-left: 0; }
  .component__head::before { display: none; }
  .job .component__body, .profile, .props--header, .inspector .component__body { padding-left: 0; }
  .print-only { display: block; }
  .print-contact { padding: 0.2rem 0 0.6rem; }
  .print-contact span { margin-right: 1.5rem; }
  /* No empty frame where the photo would be. */
  .profile { display: block; }
  .portrait { float: left; width: 6rem; margin: 0 1rem 0.5rem 0; }
  .portrait:not(:has(img)) { display: none; }
  .prop dd { padding-left: 0; border: 0; }
  .job, .project { break-inside: avoid; }
  .project { padding-left: 0; }
  a { text-decoration: none; }
}
