/* ===== Small Illustrations — case study =====
   Step 1: the skeleton. Seven sections, headings, vertical rhythm. Their
   contents land in later steps (see ILLOS_PORTFOLIO_BRIEF.md §6).

   LAYOUT IS TRANSFERRED FROM FIGMA — file OyawfANUPtP3EYv7TeNyrl, frame
   `Small Illustrations — Landing`, node 117:14315, 1440 x 5933.

   Every colour and every measurement comes from an --illos-* token in
   css/base/tokens.css, and almost every one of those is an alias to a role
   or a step the system already has. That is rule 2 and rule 3 of the brief,
   and it is why this sheet has no literal numbers in it: the structural ones
   (0, 1fr, 100%) are not design decisions.

   Inter is NOT re-declared here. Its @font-face pair lives in
   work/iconography/iconography.css and the family is a system role
   (--font-ui); a second copy of the same two declarations would be two
   things to keep in sync for no gain. What this page does need is the
   preload in its <head>, which it has. */

/* ---------------------------------------------------------------- case -- */
/* ONE article between the site's own chrome. The shell around it — sticky
   topbar, nav dock — is themed like the rest of the site, and the
   case follows the theme too rather than pinning a dark page of its own.

   That is the Iconography case's conclusion applied from the start: it
   began dark-only, and its design-system pass found the dark ground was the
   site's own --surface-page all along. The one thing here that genuinely
   cannot follow the theme is the ARTWORK's ground, and that is a token of
   its own (--illos-canvas) rather than a lock on the page.

   z-index is declared rather than left to chance: the site keeps one
   documented stacking scale, and the fixed nav dock (--z-nav 100) has to
   win over everything in here. */
.illos {
  position: relative;
  z-index: var(--z-content);
  font-family: var(--illos-font);
  font-weight: var(--illos-fw-regular);
  color: var(--illos-text);
  /* The site's body line-height is 1.6 (prose). Every text box in the source
     frame is 1.2 — the H1's 64 sets a 77 box, the section headings' 44 a 53,
     the 11px captions a 13. The layout is built on those numbers, so the
     case resets the leading once at its root rather than patching each rule
     that would otherwise inflate. */
  line-height: var(--illos-lh-tight);
  /* Long, dense page next to a lot of saturated artwork: keep the type crisp
     rather than letting the browser hint it into uneven weights. */
  -webkit-font-smoothing: antialiased;
}

/* The shared sticky topbar (css/sections/case.css) hard-codes case.css's own
   120px page padding, which would not line up with .container — and outside
   `.case` that variable is not even defined, which invalidates the whole
   shorthand and leaves the bar with no padding at all. Both problems go away
   by handing the horizontal inset to a .container inside it. Same fix, same
   reason, as .ico-topbar. */
.illos-topbar { padding: var(--space-4) 0; }
.illos-topbar__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

/* ------------------------------------------------------------ sections -- */
/* No background. The frame paints its sections #131312 over a #0E0E0D page,
   and both resolve to --surface-page, which the body already carries.
   Painting it again would be a no-op except for one thing: it is opaque, and
   it would hide .dot-grid and the shade the visitor picked under an unbroken
   slab for the whole length of the case. That is the exact conflict the
   Iconography case had to undo later; this one never creates it. */
.illos__section {
  padding-top: var(--illos-sp-section);
}

/* The last section needs a tail of its own: the sections only carry top
   padding, so without this the seventh one ends flush. It used to be the gap
   before the footer; with the footer gone it is the end of the page, and it
   also has to clear the fixed nav dock. 96 covers the 80 of --dock-space, so
   the number stands as it is. */
.illos__section--inapp { padding-bottom: var(--illos-sp-tail); }

/* --------------------------------------------------------------- type -- */
/* typography.css puts --font-display — Georgia — on every h1/h2/h3 on the
   site. That is an element selector, so it beats the family this subtree
   inherits from .illos and would silently set the case's headings in a
   serif. Handing them back to the inherited family is one rule; naming Inter
   again in three places would be three rules to keep in sync. */
.illos :is(h1, h2, h3, h4) { font-family: inherit; }

.illos__h1,
.illos__h2 {
  font-weight: var(--illos-fw-semibold);
  line-height: var(--illos-lh-tight);
  letter-spacing: normal;
  color: var(--illos-text);
}
.illos__h1 { font-size: var(--illos-fs-h1); }
.illos__h2 { font-size: var(--illos-fs-h2); }

/* Heading → content, the frame's 40 everywhere. Unlike the Iconography
   frame, no section here places its block at a different offset. */
.illos__body { margin-top: var(--illos-sp-title); }

/* ------------------------------------------------- step-1 scaffold only -- */
/* The seven empty bodies, each held open at the measured height of its block
   in the source frame so the skeleton scrolls and its rhythm can be read
   against the mock.

   These are the ONLY rules in this sheet that are scheduled for deletion:
   each one goes when its section gets content, because content is what
   should set a section's height. min-height rather than height for the same
   reason — anything that overflows must push the page, not be clipped. */
.illos__body--construction { min-height: var(--illos-h-construction); }
.illos__body--inapp        { min-height: var(--illos-h-inapp); }

/* -------------------------------------------------------------- canvas -- */
/* The dark panel the artwork sits on. This is the one surface in the case
   that does NOT follow the theme, and the reason is in the token: the
   illustrations are multicolour, they cannot be recoloured, and several carry
   white parts that stop existing on a light ground. The panel is a property
   of the artwork, so it travels with it. See DESIGN_SYSTEM.md §11. */
.illos-canvas {
  background: var(--illos-canvas);
  border-radius: var(--illos-radius);
  padding: var(--illos-canvas-pad);
}

/* ------------------------------------------------- 05 — the full set ---- */
/* Ten columns at the frame's own 80, on the page rather than on a panel.
   `space-between` rather than a declared column gap: the frame's row is 10
   cells of 80 on a 123 pitch, which needs 1187, and the site column gives
   1104 — so the cell size is kept and the gap takes the difference (~34
   against the frame's 43). The ROW pitch is exact, because 80 + 32 is 112
   either way.

   `minmax(0, …)` so the tracks can shrink rather than push the page sideways
   before the narrow-screen rules take over. */
.illos-grid {
  display: grid;
  grid-template-columns: repeat(var(--illos-grid-cols), minmax(0, var(--illos-grid-item)));
  justify-content: space-between;
  row-gap: var(--illos-grid-row-gap);
  justify-items: center;
  align-items: center;
}

/* A uniform 80 box with the artwork letterboxed inside it. The set is drawn
   to a common 80 canvas but the artwork's own boxes differ (Baseball Cap is
   80x47), and the frame centres each one in an equal cell — object-fit is
   that, in one declaration, and it keeps every row the same height. */
.illos-grid__item {
  width: var(--illos-grid-item);
  height: var(--illos-grid-item);
  object-fit: contain;
  display: block;
}

/* ------------------------------------------------- 04 — the four groups -- */
/* Two columns of equal tracks. The frame's blocks are 584 wide on a 1200
   column; equal tracks reproduce that proportion at any width, which is what
   the Iconography case had to convert its fixed plaque widths into after the
   fact. Doing it from the start costs nothing. */
.illos-cats {
  display: grid;
  grid-template-columns: repeat(var(--illos-cat-cols), 1fr);
  gap: var(--illos-cat-gap);
}

/* Each block is the same dark canvas the full set sits on — see the frame:
   four rounded indigo panels, not four bare patches of page. The artwork
   needs that ground for the same reason section 06 does. */
.illos-cat {
  padding: var(--illos-cat-pad);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.illos-cat__label {
  font-size: var(--illos-fs-label);
  font-weight: var(--illos-fw-medium);
  letter-spacing: var(--illos-ls-caps);
  color: var(--illos-text-muted);
  text-transform: uppercase;
  text-align: center;
}

/* The stage holds TWO layers, stacked, and the cross-fade swaps which one is
   opaque. Two permanent layers rather than one element whose src changes: a
   src swap shows a blank frame while the new file decodes, and it cannot
   cross-fade with itself. Grid rather than absolute positioning so the stage
   keeps its own height without one being declared. */
.illos-cat__stage {
  display: grid;
  width: var(--illos-cat-stage);
  height: var(--illos-cat-stage);
  margin-top: var(--illos-cat-label-gap);
}
.illos-cat__layer {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  transition: opacity var(--illos-cat-fade);
}
.illos-cat__layer.is-on { opacity: 1; }

.illos-cat__counter {
  margin-top: var(--illos-cat-count-gap);
  display: flex;
  align-items: baseline;
  gap: var(--illos-cat-count-x);
}
.illos-cat__n {
  font-size: var(--illos-cat-num);
  font-weight: var(--illos-fw-semibold);
  color: var(--illos-text);
  /* The number changes every couple of seconds and every glyph is a digit;
     tabular figures stop the counter shuffling sideways between 01 and 11. */
  font-variant-numeric: tabular-nums;
}
.illos-cat__total {
  font-size: var(--illos-cat-total);
  color: var(--illos-text-muted);
  font-variant-numeric: tabular-nums;
}

/* Movement off. The first illustration and 01 stay on screen, which is the
   whole section minus the cycling — brief §5. The JS checks the same query
   and never starts a timer, so this is belt and braces for the fade only. */
@media (prefers-reduced-motion: reduce) {
  .illos-cat__layer { transition: none; }
}

/* ------------------------------------------------------- 02 — palette ---- */
/* Fifteen equal columns, each a base over its shadow. The two halves are
   equal heights because that is what says they are a PAIR rather than a
   colour and a trim. */
.illos-pal__strip {
  display: grid;
  grid-template-columns: repeat(var(--illos-pal-cols), 1fr);
  border-radius: var(--illos-radius-sm);
  overflow: hidden;   /* the radius is the strip's; the columns butt together */
}
.illos-pal__swatch { display: grid; }
.illos-pal__base,
.illos-pal__shadow { height: var(--illos-pal-row); }



/* ----------------------------------------------------- 01 — the hero ---- */
/* The Hero's heading gap is its own: 114 rather than the 40 every other
   section uses. See --illos-hero-gap-title. */
.illos__section--hero .illos__body { margin-top: var(--illos-hero-gap-title); }

.illos-hero {
  display: grid;
  grid-template-columns: repeat(var(--illos-hero-cols), 1fr);
  row-gap: var(--illos-hero-row-gap);
  justify-items: center;
}

/* A slot is a STACK. Every layer sits in the same grid cell at the same size,
   so the parts of one illustration land exactly on top of each other — which
   they do, because each layer file was cut with the same viewBox as the whole
   illustration it came from. That is what makes step 7 a matter of moving one
   layer rather than of positioning anything. */
.illos-slot {
  display: grid;
  width: var(--illos-hero-slot);
  height: var(--illos-hero-slot);
}
.illos-slot__layer {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* The two state layers of Computer and Export cross-fade the same way the
   category stages do; the second starts hidden. Their transition is declared
   here so step 7 only has to swap the class. */
.illos-slot__layer[data-role="state"] {
  opacity: 0;
  transition: opacity var(--illos-cat-fade);
}
.illos-slot__layer[data-role="state"].is-on { opacity: 1; }

/* ------------------------------------------------- 01 — envelope slot ---- */
/* The envelope is not two layers cross-fading like the other state slot: the
   letter slides out of it, so the parts have to nest. Every wrapper fills the
   slot cell, so each layer keeps the illustration's own coordinates and the
   percentages below mean what the source frame means. */
.illos-env,
.illos-env__mouth,
.illos-env__letter,
.illos-env__badge {
  grid-area: 1 / 1;
  position: relative;
  width: 100%;
  height: 100%;
}
.illos-env__mouth,
.illos-env__letter,
.illos-env__badge { position: absolute; inset: 0; }

.illos-env img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* The mouth. Everything below the wings' top edge is cut away, which is why
   the letter can be parked out of sight INSIDE the envelope rather than being
   faded in over it. The V is the opening between the two front wings. */
.illos-env__mouth {
  clip-path: polygon(
    0% 0%,
    100% 0%,
    100% var(--illos-env-mouth-y),
    var(--illos-env-apex-x) var(--illos-env-apex-y),
    0% var(--illos-env-mouth-y)
  );
}

.illos-env__letter { transform-origin: 50% var(--illos-env-letter-origin-y); }
.illos-env__badge  { transform-origin: 50% var(--illos-env-badge-origin-y); }
.illos-env         { transform-origin: 50% var(--illos-env-recoil-origin-y); }

/* Only one sign is shown at a time. */
.illos-env__badge img { opacity: 0; }
.illos-env__badge img.is-on { opacity: 1; }

/* ------------------------------------------------------ 01 — sun slot ---- */
/* Inline SVG rather than an <img>: the corona's `d` is rewritten every frame,
   which nothing outside the document can reach.

   overflow visible because the corona is drawn from `lava 1`, which reaches a
   little past the illustration's own 80 box. Letting it draw outside keeps the
   sun the same size as the five slots beside it; padding the viewBox instead
   would shrink the artwork to make room for a couple of units. */
.illos-sun {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* -------------------------------------------------- 01 — monitor slot ---- */
/* Inline SVG for the same reason as the sun: the bars' heights and the disc's
   radius and stroke-width are rewritten every frame. */
.illos-mon {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
}

/* ------------------------------------------------------ project intro ---- */
/* Who made this and what it is. It sits above the palette because that is
   where the frame puts it (74:65666, "Color System"), and it is written into
   the markup rather than rendered from data: it is copy, and a visitor whose
   JS fails should still get it — the same rule the rest of the site follows. */
.illos-intro {
  line-height: var(--illos-intro-lead);
  display: grid;
  grid-template-columns: var(--illos-intro-cols);
  gap: var(--illos-intro-col-gap);
  align-items: start;
}
.illos-intro__lede {
  font-size: var(--illos-fs-body);
  color: var(--illos-text);
}

/* Role / Company / Team / Scope. A description list because that is what it
   is — four terms and their values — and the pairs sit on one line each, as
   in the frame. */
.illos-intro__meta {
  display: flex;
  flex-direction: column;
  gap: var(--illos-intro-row);
  font-size: var(--illos-fs-body);
}
.illos-intro__meta dt,
.illos-intro__meta dd { display: inline; margin: 0; }
.illos-intro__meta dt {
  font-weight: var(--illos-fw-semibold);
  color: var(--illos-text);
}
.illos-intro__meta dt::after { content: ":"; }
.illos-intro__meta dd { color: var(--illos-text-muted); }
