/* Get Less Chaos: A Place for Everything. SET IN FOAM (round 11, team C): the apps list, shared by the homepage
   (section 02) and the Apps & games page. Every app's name is cut into the board the way "Get Less Chaos" is, with
   its real icon as the full stop; the next one is a "?" that won't go home.

   UX layer (structure, layout, states) + ART DIRECTION (the look at rest). Motion, interaction and tech build on it.
   Nothing here hides content: with no script, no motion or a failed load, every name, icon, line and tape reads.

   STATES (counted in CSS with :has(), mirrored by setinfoam.js as data-count / data-band on .set)
     none   0 apps     the list is hidden; the "?" row stands alone (Apps & games page: "Empty, for now..." above it)
     one    1 app      one row, then the "?" row
     few    2-3 apps   one column of rows, names at full size
     many   4-11 apps  names one size down; 2 columns when the list is >= 880 px wide (about 1024 px windows and up)
     lots   12+ apps   as many; 3 columns when the list is >= 1160 px wide (about 1280 px windows and up)
   The "?" row is always last, always full width. Rows run oldest first.
   Windows: <= 640 px per row (phones, narrow columns): name, line, status, button stack left. <= 520 px tall: names and row
   spacing shrink so a whole row always fits on screen. Very tall: nothing grows with height.

   THE LOOK AT REST (art director): a type specimen milled into the board. No tray, no cards, no panel.
     - names: Epilogue 800 at --set-name, every letter seated flush in its own letter-shaped cut. The cut shows only
       as its kerf: a 2 px shadowed wall round each letter (finer on small names, --set-kerf) with the board's lit
       lip under it (neutral, never green), the same kerf every seated piece shows on this site. All the cuts sit
       under all the letters (.set__name is the stacking context; a letter never paints its kerf over its neighbor).
     - the full stop: the app's icon, cap height, on the baseline, in its own squircle cut (.set__dot) with the same
       kerf. The cut's floor is the app's own color (--app-color), seen only when the icon is out.
     - between rows: one long milled groove (a router kerf with rounded ends), close above the next name, like the rule
       over each entry of a specimen sheet. At least 2x the name's size from row to row.
     - status: label tape, on the right (left under the line in narrow rows). The "?" row's tape takes the same place,
       so the right edge reads as one column of labels.
     - the "?" row: the "?" at name size in the logo's a-pose over its own green "?"-shaped pocket, its soft shadow in
       the hole, and an empty neutral squircle cut in the full stop's place. The only green at rest.
   Light and dark come from the tokens (--kerf, --lip-a, --cut-*, --floor-*). */

.set {
  --set-name: var(--text-3xl);                 /* 1-3 apps: bigger than the section heading, smaller than About's */
  --set-gap: 2em;                              /* row to row, in name ems: 2x the name (art director) */
  --set-icon: .7375em;                         /* the icon full stop: the cap height (the logo's cap, 73.75 / 100) */
  --set-q-lift: .82em;                         /* the "?" hovers 1.08x its own height (the logo's a-pose) */
  container: set / inline-size;
}
/* the Apps & games page: its h1 stays the page's biggest line (as About's does on the homepage), so its names sit one
   step under it, at the homepage section heading's size (88 px h1 over 68 px names at 1440, instead of 88 over 78) */
.page .set { --set-name: clamp(2.25rem, 1.4rem + 3vw, 4.25rem); }
.set:has(.set__list > .set__item:nth-child(4)), .set[data-band="many"], .set[data-band="lots"] { --set-name: var(--text-2xl); }
@media (max-height: 520px) and (orientation: landscape) {
  .set { --set-name: min(var(--text-3xl), 15vh); --set-gap: 1.3em; }   /* 1-3 apps; 4+ keep their smaller size */
  .page .set { --set-name: min(clamp(2.25rem, 1.4rem + 3vw, 4.25rem), 15vh); }
}

/* ---------------------------------------------------------------- the list: one row per app */
.set__list { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: minmax(0, 1fr); column-gap: var(--space-8); }
.set__list:not(:has(> .set__item)), .set[data-band="none"] .set__list { display: none; }
@container set (min-width: 880px) {
  .set__list:has(> .set__item:nth-child(4)) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container set (min-width: 1160px) {
  .set__list:has(> .set__item:nth-child(12)) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* each row is its own container, so its name fits its own column and its parts stack when it is narrow */
.set__item {
  container-type: inline-size;
  position: relative;
  font-size: var(--set-name);
  /* the groove sits at the bottom of each row: 0.3 of the gap above a name, 0.7 below its status (the rule belongs
     to the entry under it, as on a specimen sheet) */
  padding-block: calc(var(--set-gap) * .3) calc(var(--set-gap) * .7);
}
/* the first row (of each column) has no groove above it, only air: enough that its loose handful and its squared-up
   line land on open board, never over the section head's paragraph (or the Apps & games page's subtitle) above it
   (creative director, r11-c: the arrival used to tumble across that paragraph on desktop) */
.set__item:first-child { padding-top: var(--set-air, .6em); }
@container set (min-width: 880px) { .set__list:has(> .set__item:nth-child(4)) > .set__item:nth-child(2) { padding-top: var(--set-air, .6em); } }
@container set (min-width: 1160px) { .set__list:has(> .set__item:nth-child(12)) > .set__item:nth-child(3) { padding-top: var(--set-air, .6em); } }
:where(.set__item) > * { font-size: var(--text-md); }

/* the groove: a long router kerf cut between rows. Its far wall in shadow, its floor the kerf, the board's lit lip
   under its near edge; rounded where the bit went in and came out. Neutral in both themes. */
.set__item::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 4px; border-radius: 4px;
  background: linear-gradient(var(--cut-edge-a), transparent 2px), var(--kerf);
  box-shadow: inset 0 1px 1px var(--cut-ao-a), 0 1px 0 var(--lip-a);
  pointer-events: none;
}

/* the row's anatomy: the name (with its icon as the full stop), then the line, then the status */
.set__app, .set__next {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--space-7); row-gap: var(--space-4); align-items: start;
}
.set__app { grid-template-areas: "name name" "line status" "btn btn"; }
@container (max-width: 640px) {
  .set__app { grid-template-columns: minmax(0, 1fr); grid-template-areas: "name" "line" "status" "btn"; row-gap: var(--space-3); }
}
/* the way to the app's page, under the line: the same small button as the "?" row's (user, 2026-10-26) */
.set__app > .btn { grid-area: btn; justify-self: start; margin-top: var(--space-2); }
.set__app > .btn .btn__piece { min-height: 44px; }   /* a 44 px target */

/* the name: real text, Epilogue 800; scripts split it into aria-hidden letters (words never break inside) */
.set__name {
  grid-area: name; margin: 0;
  font-family: var(--font-display); font-weight: var(--weight-black);
  /* --w = the longest word in letters (+ the icon on the last word), set by setinfoam.js: a long word shrinks to fit
     its column instead of overflowing; without the script the size simply stays the design's */
  font-size: min(var(--set-name), calc(100cqi / (var(--w, 1) * .68)));
  line-height: 1.05; letter-spacing: var(--tracking-display); color: var(--ink);
  max-width: none; overflow-wrap: anywhere;
  isolation: isolate;                          /* every cut (kerf, lip, pocket) sits under every letter */
  --set-kerf: clamp(1px, .026em, var(--space-kerf));   /* the kerf: 2 px on a full-size name, finer on a small one */
}
.set__link { color: inherit; text-decoration: none; }   /* the name and icon are the link to the app's page */
.set__letters { display: inline; }
.set__w { white-space: nowrap; }
/* a letter: stationary, it keeps the place and the cut (move a piece inside it, never the letter's own span).
   isolation stays auto even when a pocket is attached (LetterSlot isolates its span): an isolated letter would paint
   its own kerf over its neighbor where the two are closer than the kerf. */
.set__l { display: inline-block; position: relative; isolation: auto !important; }
/* its cut at rest: the 2 px kerf round the letter (a stroke centered on the letter's own outline: the inner half is
   under the letter) and, 1 px lower, the board's lit lip under the kerf */
.set__l::before, .set__l::after {
  content: attr(data-ch); position: absolute; left: 0; top: 0; pointer-events: none; white-space: pre;
  color: transparent; -webkit-text-stroke: calc(var(--set-kerf) * 2) var(--kerf);
}
.set__l::before { z-index: -2; }
.set__l::after { z-index: -3; -webkit-text-stroke-color: var(--lip-a); transform: translateY(1px); }

/* the full stop: the app's icon, cap height, on the baseline, a period's space after the last letter */
.set__icon {
  display: inline-block; width: var(--set-icon); height: var(--set-icon);
  margin-left: .08em; vertical-align: baseline;
  border-radius: 23%; object-fit: cover;
}
/* no script: the icon has no separate cut, so it carries its kerf itself */
.set__name > .set__icon, .set__link > .set__icon { box-shadow: 0 0 0 var(--space-kerf) var(--kerf), 0 1px 0 var(--space-kerf) var(--lip-a); }
/* its cut (setinfoam.js): a squircle pocket in the board with the same kerf; the floor is the app's own color, lit
   like every pocket here (darker under the far wall, brighter toward the near rim) and seen only while the icon is out */
.set__dot {
  --app: var(--app-color, var(--foam));
  position: relative; display: inline-block; vertical-align: baseline;
  width: var(--set-icon); height: var(--set-icon); margin-left: .08em;
  border-radius: 23%;
  box-shadow: 0 0 0 var(--space-kerf) var(--kerf), 0 1px 0 var(--space-kerf) var(--lip-a);
}
.set__dot::before {
  content: ""; position: absolute; inset: 1px; border-radius: inherit; pointer-events: none;
  background: linear-gradient(color-mix(in oklab, var(--app) 70%, #000), color-mix(in oklab, var(--app) 90%, #fff));
  box-shadow: inset 1px 6px 0 -1px rgba(0, 0, 0, .42), inset 3px 14px 18px -6px rgba(0, 0, 0, .36);
}
.set__dot > .set__icon { position: relative; display: block; width: 100%; height: 100%; margin: 0; }

.set__line { grid-area: line; margin: 0; max-width: 40ch; font-size: var(--text-lg); color: var(--ink-2); }
/* the status: label tape, level with the line's first line */
.set__status { grid-area: status; margin: .3em 0 0; justify-self: end; }
.set__status .tag { transform: rotate(-1deg); }
@container (max-width: 640px) { .set__status { justify-self: start; margin-top: var(--space-1); } }

/* ---------------------------------------------------------------- the "?" row: the next one, same anatomy */
.set__next {
  font-size: var(--set-name);
  padding-block: calc(var(--set-gap) * .3) 0;
  /* the "?" and its empty full stop; the line with the tape in the status's place; the button under the line */
  grid-template-areas: "name name" "wait tape" "btn btn";
  container-type: inline-size;
}
.set__list:not(:has(> .set__item)) + .set__next, .set[data-band="none"] .set__next { padding-top: 0; }
:where(.set__next) > :where(:not(.set__qname)) { font-size: var(--text-md); }
.set__qname {
  grid-area: name; display: inline-flex; align-items: baseline; justify-self: start;
  padding-top: var(--set-q-lift);
  font-family: var(--font-display); font-weight: var(--weight-black);
  line-height: 1.05; letter-spacing: var(--tracking-display); color: var(--ink);
}
/* the "?": .set__q is its stationary cut (the pocket lives here), .set__qp the piece, held in the logo's a-pose
   (lifted 1.08x its height, turned -9 deg about its foot, nudged 5%); static, so it holds with no script and in
   reduced motion */
.set__q { position: relative; display: inline-block; isolation: isolate; }
.set__qp { display: inline-block; transform: translate(.05em, calc(-1 * var(--set-q-lift))) rotate(-9deg); transform-origin: 20% 100%; }
/* no logo.js: a flat green "?" stands in for the cut (the system's fallback for a waiting letter) */
.set__q:not(.has-slot)::before {
  content: attr(data-ch); position: absolute; left: 0; top: 0; z-index: -1; pointer-events: none;
  color: var(--foam); text-shadow: 0 1px 0 var(--lip-a);
}
/* the empty full stop: a neutral squircle cut, nothing in it yet (no green: nothing has arrived) */
.set__icon--empty {
  margin-left: .1em;
  background: linear-gradient(var(--cut-floor-top), var(--cut-floor-bot));
  box-shadow: inset 0 0 0 var(--space-kerf) var(--kerf), var(--z-cut-2);
}
.set__next .tag--tape { grid-area: tape; justify-self: end; align-self: start; margin-top: .3em; }
.set__wait { grid-area: wait; margin: 0; max-width: 40ch; font-size: var(--text-lg); color: var(--ink-2); }
.set__next .btn { grid-area: btn; justify-self: start; margin-top: var(--space-2); }
@container (max-width: 640px) {
  .set__next { grid-template-columns: minmax(0, 1fr); grid-template-areas: "name" "wait" "tape" "btn"; row-gap: var(--space-3); }
  .set__next .tag--tape { justify-self: start; margin-top: var(--space-1); }
}
.set__next .btn .btn__piece { min-height: 44px; }   /* a 44 px target */

/* tech: browsers without container queries (before Chrome 105 / Safari 16) read the window instead of the row: the
   rows stack on phones and a long name shrinks to the window, so nothing runs off the side. Modern browsers skip this. */
@supports not (container-type: inline-size) {
  .set__name { font-size: min(var(--set-name), calc(88vw / (var(--w, 1) * .68))); }
  @media (max-width: 700px) {
    .set__app { grid-template-columns: minmax(0, 1fr); grid-template-areas: "name" "line" "status" "btn"; row-gap: var(--space-3); }
    .set__status { justify-self: start; margin-top: var(--space-1); }
    .set__next { grid-template-columns: minmax(0, 1fr); grid-template-areas: "name" "wait" "tape" "btn"; row-gap: var(--space-3); }
    .set__next .tag--tape { justify-self: start; margin-top: var(--space-1); }
  }
}

/* ---------------------------------------------------------------- around the list */
.set + .shelf__note { margin-top: var(--space-7); }

/* forced colors: no cuts or decoration, just the words (every pocket hidden, the letter pockets too: a brushed or
   carried letter lifts over plain board, never over a green hole) */
@media (forced-colors: active) {
  .set__l::before, .set__l::after, .set__q::before, .set__dot::before, .set__item::after { content: none; }
  .set .glc-letter-slot { display: none !important; }   /* !important: LetterSlot writes display inline */
  .set__qp { transform: none; }
  .set__dot, .set__name > .set__icon, .set__link > .set__icon { box-shadow: none; }
  .set__icon--empty { border: 1px solid CanvasText; background: none; box-shadow: none; }
  .set__item { border-bottom: 1px solid CanvasText; }
}

/* ---------------------------------------------------------------- MOTION (motion designer; run by setinfoam.js)
   A letter's piece (.set__lp) moves inside its stationary span; the icon moves inside its .set__dot; the tape is its
   .set__status. Poses are inline transforms in ems. While a piece is off the board (--lift, ems) it casts a soft shadow,
   and it never casts one at rest. */
.set__lp { display: inline-block; transform-origin: 50% 100%; }
.set__dot > .set__icon { transform-origin: 50% 100%; }
.set__status { transform-origin: 100% 60%; }
/* seams pass (r20-final): on the dark board black at 24% can't be seen, so a carried letter floated with no shadow.
   In dark mode the shadow is 2.5 times stronger (60%), the same rule as 404 A's "?" and 404 B's pieces; light is unchanged */
.set { --set-sh: 24%; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .set { --set-sh: 60%; } }
[data-theme="dark"] .set { --set-sh: 60%; }
[data-theme="light"] .set { --set-sh: 24%; }
.set__lp[style*="--lift"] { text-shadow: 0 calc(var(--lift) * .3em) calc(var(--lift) * .45em) color-mix(in srgb, var(--shadow) var(--set-sh), transparent); }
.set__dot > .set__icon[style*="--lift"] { box-shadow: 0 calc(var(--lift) * .3em) calc(var(--lift) * .45em) color-mix(in srgb, var(--shadow) var(--set-sh), transparent); }
/* before a row arrives (motion only): the name shows as its holes (green letter pockets, the icon's pocket in the app's
   color); the letters, the icon and the tape wait off the board. The line always shows. On a first visit the "?" waits
   too, over its empty pocket. Whatever happens to the scripts, html.failsafe shows everything. */
html.motion .set__item.is-pre .set__lp,
html.motion .set__item.is-pre .set__dot > .set__icon,
html.motion .set__item.is-pre .set__status,
html.motion .set__next.is-pre .set__qp { opacity: 0; }
html.failsafe .set .is-pre .set__lp,
html.failsafe .set .is-pre .set__dot > .set__icon,
html.failsafe .set .is-pre .set__status,
html.failsafe .set .is-pre .set__qp { opacity: 1 !important; }

/* ---------------------------------------------------------------- INTERACTION (interaction designer; run by setinfoam.js)
   A piece in the hand is drawn above everything in the set (its own row over the next, its name over the row's line and
   tape, the piece over its neighbors), while its stationary span keeps the open cut underneath. The site header stays
   on top. With motion on, the name's letters can't be selected or long-pressed into a callout (the heading still
   carries the whole name for reading, search and screen readers). */
html.motion .set__letters, html.motion .set__qname {
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
}
html.motion .set__icon { -webkit-user-drag: none; }
.set.is-carrying { position: relative; z-index: 30; }
.set__item.is-held { z-index: 2; }
.set__item.is-held .set__name { position: relative; z-index: 3; }
.set__next.is-held { position: relative; z-index: 2; }
.set__next.is-held .set__qname { position: relative; z-index: 3; }
.set__l.is-held > .set__lp { position: relative; z-index: 5; }
.set__dot.is-held > .set__icon { z-index: 5; }
html.set-carrying, html.set-carrying * { cursor: grabbing !important; }
