/*
  Warm brutalism.

  Brutalist usually means concrete: cold grey, hard edges, no mercy. The warm
  version of that is not a softer grey, it is a different material. This one is
  manila. A card folder is already a brutalist object, cheap and structural and
  honest about what it is made of, and it happens to be the warmest surface in
  any office. For a consultancy that handles the paperwork of a creative life,
  that is also just true.

  Hard edges stay: no border radius anywhere, black rules with real weight,
  panels that sit on the page like filed documents. The warmth is in the stock
  and the ink, not in the corners.

  Nothing here is cream (#f4f1ea) and nothing is terracotta. Those two turn up
  together on every generated page on the internet.
*/

:root {
  --manila: #e0cfa9;
  --manila-deep: #cbb98f;
  --ink: #14110d;
  --oxblood: #6f2015;
  --ochre: #8a6b2a;

  --rule: 2px solid var(--ink);
  --rule-heavy: 5px solid var(--ink);
}

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

html {
  background: var(--manila);
}

body {
  margin: 0;
  background: var(--manila);
  color: var(--ink);
  font-family: "Courier Prime", "Courier New", monospace;
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

/* The organism lives under everything and is not interactive. */
#growth {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  pointer-events: none;
}

.sheet {
  position: relative;
  z-index: 1;
  max-width: 68rem;
  margin: 0 auto;
  padding: 3rem 1.5rem 6rem;
}

/*
  Every block of content is an opaque manila panel with a hard black edge.
  That opacity is doing two jobs: it keeps text off the growth so nothing
  becomes unreadable, and it gives the aggregation something to grip. The
  perimeter of each of these is the seed. The layout is the substrate.
*/
.panel {
  position: relative;
  background: var(--manila);
  border: var(--rule);
  padding: 1.5rem;
  margin-bottom: 1.75rem;
}

.panel--heavy {
  border: var(--rule-heavy);
}

/*
  The shadow is engraved, not cast.

  A hard offset slab is the one move every neo-brutalist page has made for
  the last four years, and a solid black rectangle is not how a printed
  catalogue ever showed depth anyway. It showed it with a hatch: ruled
  diagonal lines, cut denser where the shade was meant to be darker. So the
  offset block is still there, still hard-edged, still down and to the
  right, but it is ruled rather than filled, and the manila shows between
  the lines the way paper does under an engraving.

  It sits behind the panel's own background rather than beside it, so only
  the offset part is ever visible.
*/
.panel--slab {
  box-shadow: none;
}

.panel--slab::after {
  content: "";
  position: absolute;
  inset: 10px -10px -10px 10px;
  z-index: -1;
  background: repeating-linear-gradient(
    45deg,
    var(--ink) 0 2px,
    transparent 2px 5px
  );
}

/* The heavy panels get a tighter rule, so they read as the darker shade. */
.panel--heavy.panel--slab::after {
  background: repeating-linear-gradient(
    45deg,
    var(--ink) 0 3px,
    transparent 3px 5px
  );
}

.wordmark {
  font-family: "Archivo Black", "Arial Black", sans-serif;
  font-weight: 400;
  /* Four characters on one line, so it can run far larger than the
     three-line spelling did and still sit inside the panel. */
  font-size: clamp(4rem, 28vw, 18rem);
  /* Archivo Black descends ~0.2em; a tighter line-height than that lets
     the y hang through the panel rule. */
  line-height: 1.05;
  letter-spacing: -0.03em;
  margin: 0;
  text-transform: lowercase;
}

.stamp {
  display: inline-block;
  border: var(--rule);
  background: var(--oxblood);
  color: var(--manila);
  padding: 0.2rem 0.6rem;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.meta {
  margin: 0;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.lede {
  font-size: clamp(1rem, 2.2vw, 1.25rem);
  max-width: 46ch;
  margin: 0;
}

.cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.75rem;
}

@media (min-width: 60rem) {
  .cols--2 {
    grid-template-columns: 1.4fr 1fr;
  }
  .cols--3 {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* A roster reads as a filed list, so it is ruled like one. */
.roster {
  list-style: none;
  margin: 0;
  padding: 0;
}

.roster li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.55rem 0;
  border-bottom: 1px dashed rgba(20, 17, 13, 0.45);
}

.roster li:last-child {
  border-bottom: 0;
}

.roster .disc {
  color: var(--oxblood);
  text-transform: uppercase;
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  white-space: nowrap;
  align-self: center;
}

h2 {
  font-family: "Archivo Black", "Arial Black", sans-serif;
  font-weight: 400;
  font-size: 1.05rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin: 0 0 0.9rem;
  padding-bottom: 0.5rem;
  border-bottom: var(--rule);
}

a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 2px;
}

a:hover {
  background: var(--oxblood);
  color: var(--manila);
}

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

.note {
  font-size: 0.8rem;
  line-height: 1.5;
  margin: 0;
}

.dim {
  color: rgba(20, 17, 13, 0.62);
}

/*
  ---------------------------------------------------------------------------
  The control room.

  A settings panel is a filing problem, which this page already has an
  answer to: manila stock, black rules, nothing rounded, nothing floating on
  a soft shadow. So the modal is a heavier panel, a dial readout is a stamp,
  a slider is a black block on a ruled line, and a totem is a filed card
  small enough to pick up. None of it introduces a new material.
  ---------------------------------------------------------------------------
*/

:root {
  --moss: #40562c;
}

/* Our own components own their hiding; .modal is display:flex otherwise. */
.nav__btn[hidden],
.modal[hidden],
.chest[hidden],
.set[hidden] {
  display: none;
}

/* The nav ------------------------------------------------------------- */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 1.5rem;
  background: var(--manila);
  border-bottom: var(--rule);
}

.nav__mark {
  margin: 0;
  font-family: "Archivo Black", "Arial Black", sans-serif;
  font-size: 1rem;
  letter-spacing: -0.02em;
  text-transform: lowercase;
}

.nav__acts {
  display: flex;
  gap: 0.5rem;
}

.nav__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  background: var(--manila);
  color: var(--ink);
  border: var(--rule);
  padding: 0.35rem 0.7rem;
  font: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
}

.nav__btn--heavy {
  border-width: 3px;
}

.nav__btn:hover:not(:disabled),
.nav__btn[aria-expanded="true"] {
  background: var(--oxblood);
  color: var(--manila);
}

.nav__btn:disabled {
  opacity: 0.45;
  cursor: default;
}

/* The nav is fixed, so the sheet starts below where it sits. */
.sheet {
  padding-top: 5rem;
  transition: opacity 0.6s ease, visibility 0s;
}

/*
  Clearing the deck. The writing does not get deleted, it gets taken out of
  the way — hidden rather than faded, because the growth reads the panels as
  the wall it climbs and an invisible wall is still a wall.
*/
.deck-clear .sheet {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.6s ease, visibility 0s linear 0.6s;
}

/* The totems ---------------------------------------------------------- */

.totems {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  z-index: 3;
  pointer-events: none;
}

/*
  Centred on its point with margins rather than a translate. A transform
  would make the totem its own stacking context, and the engraved hatch
  behind it is a z-index:-1 pseudo-element: inside a stacking context that
  paints over the card instead of under it, and the glyph disappears into
  the ruling. Everything else on this page hatches the same way.
*/
.totem {
  position: absolute;
  margin: -1.5rem 0 0 -1.5rem;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  padding: 0;
  background: var(--manila);
  color: var(--ink);
  border: var(--rule);
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
  transition: background 0.12s ease, color 0.12s ease;
}

.totem::after {
  content: "";
  position: absolute;
  inset: 6px -6px -6px 6px;
  z-index: -1;
  background: repeating-linear-gradient(
    45deg,
    var(--ink) 0 2px,
    transparent 2px 5px
  );
}

/* Held reads as a colour flip, for the same reason: no transform. */
.totem.is-held {
  cursor: grabbing;
  background: var(--oxblood);
  color: var(--manila);
}

.totem[data-kind="stone"] {
  background: var(--ink);
  color: var(--manila);
}

.totem[data-kind="lamp"] {
  color: var(--ochre);
}

.totem[data-kind="eye"] {
  color: var(--oxblood);
}

.totem[data-kind="sprout"] {
  color: var(--moss);
}

/* The chest ----------------------------------------------------------- */

/*
  Above the modal on purpose. The chest is opened from inside the panel and
  is meant to be dragged from immediately, so it has to sit over the scrim
  rather than behind it; the first press on a toy closes the panel anyway.
*/
.chest {
  position: fixed;
  left: 1rem;
  bottom: 1rem;
  z-index: 45;
  width: max-content;
  max-width: min(24rem, calc(100vw - 2rem));
  padding: 0.75rem 0.85rem 0.85rem;
  background: var(--manila);
  border: var(--rule-heavy);
}

.chest__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.6rem;
}

.chest__title {
  margin: 0;
  font-family: "Archivo Black", "Arial Black", sans-serif;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.chest__acts {
  display: flex;
  gap: 0.3rem;
}

.chest__btn {
  background: var(--manila);
  color: var(--ink);
  border: var(--rule);
  padding: 0.1rem 0.4rem;
  font: inherit;
  font-size: 0.64rem;
  line-height: 1.3;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

.chest__btn:hover {
  background: var(--oxblood);
  color: var(--manila);
}

.chest__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.chest__toy {
  display: grid;
  justify-items: center;
  gap: 0.25rem;
  width: 3.5rem;
  padding: 0.4rem 0.2rem;
  background: var(--manila);
  color: var(--ink);
  border: var(--rule);
  font: inherit;
  font-size: 0.58rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: grab;
  touch-action: none;
}

.chest__toy:hover {
  background: var(--oxblood);
  color: var(--manila);
}

.chest__hint {
  margin: 0.6rem 0 0;
  font-size: 0.68rem;
  line-height: 1.4;
  color: rgba(20, 17, 13, 0.62);
}

/* The modal ----------------------------------------------------------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.modal__scrim {
  position: absolute;
  inset: 0;
  background: rgba(20, 17, 13, 0.6);
}

.modal__box {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(46rem, 100%);
  max-height: min(46rem, calc(100vh - 2rem));
  background: var(--manila);
  border: var(--rule-heavy);
}

.modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1.25rem;
  border-bottom: var(--rule);
}

.modal__head h2 {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 1.1rem;
}

.modal__x {
  background: var(--manila);
  color: var(--ink);
  border: var(--rule);
  width: 2rem;
  height: 2rem;
  font: inherit;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.modal__x:hover {
  background: var(--oxblood);
  color: var(--manila);
}

.modal__body {
  overflow-y: auto;
  padding: 1.25rem;
}

.modal__foot {
  padding: 0.6rem 1.25rem;
  border-top: var(--rule);
}

.modal__foot p {
  margin: 0;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
}

.set {
  margin-bottom: 1.9rem;
}

.set:last-child {
  margin-bottom: 0;
}

.set h3 {
  font-family: "Archivo Black", "Arial Black", sans-serif;
  font-weight: 400;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin: 0 0 0.7rem;
  padding-bottom: 0.4rem;
  border-bottom: var(--rule);
}

.row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.press {
  background: var(--manila);
  color: var(--ink);
  border: var(--rule);
  padding: 0.4rem 0.7rem;
  font: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

.press:hover {
  background: var(--oxblood);
  color: var(--manila);
}

.press--heavy {
  background: var(--ink);
  color: var(--manila);
  border-width: 3px;
}

.press--swatch {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}

.press--swatch::before {
  content: "";
  width: 0.7rem;
  height: 0.7rem;
  background: var(--swatch);
  box-shadow: inset -0.35rem 0 0 var(--swatch-2);
  outline: 1px solid var(--ink);
}

.press--swatch.is-on {
  background: var(--ink);
  color: var(--manila);
}

/* A dial -------------------------------------------------------------- */

.dial {
  margin-bottom: 1rem;
}

.dial__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.dial__label {
  font-size: 0.76rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The readout is a stamp, the same object the page uses elsewhere. */
.dial__out {
  background: var(--ink);
  color: var(--manila);
  padding: 0.05rem 0.4rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}

/*
  A slider with a round thumb would be the only curve on the page. This one
  is a black block riding a ruled line.
*/
.dial input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 1.6rem;
  margin: 0.15rem 0 0;
  background: transparent;
  cursor: ew-resize;
}

.dial input[type="range"]::-webkit-slider-runnable-track {
  height: 3px;
  background: var(--ink);
}

.dial input[type="range"]::-moz-range-track {
  height: 3px;
  background: var(--ink);
}

.dial input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 0.85rem;
  height: 1.4rem;
  margin-top: -0.67rem;
  background: var(--oxblood);
  border: 2px solid var(--ink);
}

.dial input[type="range"]::-moz-range-thumb {
  width: 0.85rem;
  height: 1.4rem;
  border-radius: 0;
  background: var(--oxblood);
  border: 2px solid var(--ink);
}

/* A switch ------------------------------------------------------------ */

.switch {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.7rem;
}

.switch input[type="checkbox"] {
  position: relative;
  -webkit-appearance: none;
  appearance: none;
  width: 1.15rem;
  height: 1.15rem;
  margin: 0;
  background: var(--manila);
  border: var(--rule);
  cursor: pointer;
}

.switch input[type="checkbox"]:checked {
  background: var(--ink);
}

.switch input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  inset: 3px;
  background: var(--manila);
}

.switch__label {
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

@media (max-width: 40rem) {
  .nav {
    padding: 0.45rem 1rem;
  }

  .nav__btn {
    font-size: 0.66rem;
    padding: 0.3rem 0.5rem;
  }

  .chest {
    left: 0.5rem;
    right: 0.5rem;
    bottom: 0.5rem;
    width: auto;
    max-width: none;
  }

  .modal {
    padding: 0.5rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sheet,
  .totem {
    transition: none;
  }
}
