/* page-entry.css — the entry surfaces: /lifecycle/, /projects/, /login/, /guide/.
   These are content screens, not a HUD over the 3D world, so they are allowed
   room. What they share with the viewer's console is the material: machined
   plates with one chamfer, one bevel, one hairline, warm status light.

   ONE VOCABULARY. This block and the blocks at the top of page-data.css,
   page-tool.css, page-account.css and /pdf/pdf.css are the same names carrying
   the same values. Where two of them once disagreed — the upper rim, the
   chamfer sizes, the spacing steps, the ink ramp, the ground, `--sc-hair` (a
   LENGTH here, a COLOUR there) — one value won and all five carry it. Only the
   final "the page's own scale" section is allowed to differ, because a hub's
   column width is not a material constant.

   SCOPED TO THE FOUR BODY CLASSES, never :root. Every region wrote to :root at
   first and they silently overwrote each other's materials by load order. A
   block one level down cannot be beaten by another sheet's :root, which is the
   whole point. */

/* ---- TOKENS: rebased onto the material system ---- */
body.pg-lifecycle, body.pg-projects, body.pg-login, body.pg-guide {
  /* -- ground and recesses ----------------------------------------------
     The ground is deliberately NOT at the black floor. A plate can only cast
     a shadow if there is something left under it to darken; on #04070a the
     deepest shadow available was one RGB level, so every plate read as a
     sticker. The whole ramp lifts together, and the plates stay clearly
     above their housing. */
  --sc-ground:      #0a1017;   /* the housing everything is bolted to       */
  --sc-well:        #060c11;   /* a recessed well, an input — BELOW ground  */
  --sc-well-lo:     #04080c;   /* the bottom of a well, further from light  */
  --sc-plate:       #0e1820;   /* a plate face                              */
  --sc-plate-hi:    #16242e;   /* the lit top of a plate face               */
  --sc-plate-lo:    #0a121a;   /* the shaded bottom of a plate face         */
  --sc-plate-lit:   #12242c;   /* a plate face under the cursor             */
  --sc-plate-hot:   #0c1a22;   /* a plate face carrying the accent          */
  /* the metal ramp the rail beam is cut from — the same three stops the tool,
     data and account sheets use, so the app has ONE rail material */
  --sc-st-3:        #34383e;
  --sc-st-1:        #181b1e;
  --sc-metal-short: linear-gradient(180deg,
                    #727983 0, #5d646d 42%, #4a5058 82%, #3d434a 100%);
  --sc-socket:      linear-gradient(180deg, #1b2329 0, #101820 46%, #080d11 100%);
  --sc-socket-lit:  linear-gradient(180deg, #16333b 0, #0e2831 45%, #071820 100%);
  --sc-warm-rim:    rgba(255, 196, 112, .14);
  --sc-seat:        rgba(0, 0, 0, .45);        /* the line a key sits in    */
  --sc-glass:       rgba(255, 255, 255, .10);  /* a lit edge on a dark part */
  --sc-tx-sh:       rgba(0, 0, 0, .9);         /* type cut into lit metal   */
  --sc-shadow:      rgba(0, 0, 0, .75);        /* the dark inside a socket  */
  --sc-cy-glow:     rgba(108, 242, 255, .50);
  --sc-brushed: repeating-linear-gradient(90deg,
                    var(--sc-sheen) 0 1px, rgba(0,0,0,.022) 1px 4px);

  /* -- edges: ONE width, three opaque steps, one hairline ---------------- */
  --sc-edge-w:      1px;       /* the machined edge, one width, everywhere  */
  --sc-edge:        #17323e;   /* the structural line                       */
  --sc-edge-soft:   #122630;   /* an interior seam                          */
  --sc-edge-lit:    #2b6b7d;   /* an edge under light                       */
  --sc-sheen:       rgba(255, 255, 255, .022); /* the faintest lit wash     */
  --sc-grid:        rgba(120, 200, 225, .030); /* background hairline grid  */
  --sc-limb:        rgba(120, 205, 235, .085); /* the one arc in the sky    */

  /* -- THE EDGE ASSEMBLY ------------------------------------------------
     A plate is not a stroke. Down a vertical line through one there are five
     strata, in this order:

       1  RIM      a light upper rim, 1px, where the top plane catches light
       2  LIP      a dark lip immediately inside it — the chamfer's shadow
       3  FACE     the field, a top-lit ramp from --sc-plate-hi to -lo
       4  RETURN   a dimmer rim at the bottom, over its own dark under-lip:
                   the plate's underside, seen because the plate has thickness
       5  CAST     a shadow beneath, darker than the ground at contact and
                   ramping back to it over ~12px

     A lit top with no shadowed bottom reads as a fade, not a plate, so 4 and
     5 are never applied without each other. */
  --sc-rim-hi:      rgba(190, 242, 255, .34);  /* 1  the specular upper rim */
  --sc-lip:         rgba(0, 0, 0, .58);        /* 2  the dark inner lip     */
  --sc-rim-lo:      rgba(150, 214, 236, .14);  /* 4  the lower return       */
  --sc-under:       rgba(0, 0, 0, .55);        /* 4  dark under that return */
  --sc-bevel-lo:    rgba(0, 0, 0, .72);        /*    the line under a beam  */
  --sc-cast-1:      rgba(0, 0, 0, .80);        /* 5  the contact shadow     */
  --sc-cast-2:      rgba(0, 0, 0, .55);        /* 5  the soft cast shadow   */
  --sc-cast-y1:     1px;  --sc-cast-b1:  2px;
  --sc-cast-y2:     6px;  --sc-cast-b2: 12px;  /* a plate                   */
  --sc-cast-y3:     2px;  --sc-cast-b3:  5px;  /* a small part: key, chip   */

  /* -- light ------------------------------------------------------------- */
  --sc-cy:          #6cf2ff;
  --sc-cy-2:        #2f8296;   /* the accent, held back                     */
  --sc-cy-line:     rgba(108, 242, 255, .32);
  --sc-cy-wash:     rgba(108, 242, 255, .10);
  --sc-am:          #ffb340;   /* the primary action, and only that         */
  --sc-am-hi:       #ffd08a;   /* the primary action, under the cursor      */
  --sc-am-tx:       #ffdca6;
  --sc-am-edge:     #4a3512;
  --sc-am-wash:     rgba(255, 179, 64, .10);
  --sc-am-wash-2:   rgba(255, 179, 64, .18);
  --sc-gn:          #3dffb1;
  --sc-gn-edge:     #14483a;
  --sc-rd:          #ff5c7a;
  --sc-hatch:       rgba(120, 170, 190, .05);  /* the "not built" hatching  */
  --sc-inset-lo:    rgba(0, 0, 0, .55);
  --sc-sky-1:       rgba(56, 140, 172, .16);
  --sc-sky-2:       rgba(30, 92, 122, .13);

  /* -- ink: four rungs, and EVERY one clears 4.5:1 on the surface it is
     printed on. The old bottom rung measured 2.71:1 on a PLANNED card; a
     hierarchy whose bottom step is unreadable has three steps, not four. */
  --sc-tx-hi:       #eef6fa;
  --sc-tx:          #c3d0d8;
  --sc-tx-dim:      #8ba7b3;
  --sc-tx-off:      #7e8f9a;   /* the dimmest ink there is                  */
  --sc-tx-max:      #fff;      /* one word, once, in the masthead           */
  /* accent-as-INK. --sc-cy-2 is a good edge and a poor 11px letter: the
     kicker, the page's own first line, measured 4.37:1 in it. */
  --sc-cy-ink:      #57b6cd;   /*  7.7:1 on a plate face                    */

  /* -- geometry: three chamfers on the 4px grid --------------------------
     45 degrees always, and the three sizes are 16 / 8 / 4 — the spacing
     scale's own steps, so every cut lands on a whole pixel at 1x and at 2x.
     Nothing is rounded except a status light. */
  --sc-ch-lg:       16px;
  --sc-ch-md:       8px;
  --sc-ch-sm:       4px;
  --sc-radius:      2px;       /* pips, tags — nothing else is rounded      */
  --sc-radius-dot:  50%;       /* a status light, and only that             */
  --sc-bar:         2px;       /* ONE emphasis bar width, everywhere        */
  --sc-focus-w: 3px;    /* ONE focus-ring width, everywhere */
  --sc-hatch-pitch: 6px;
  /* The inner cut that leaves exactly --sc-edge-w along the diagonal too.
     The face layer is inset 1px, so in the plate's own coordinates its
     diagonal sits at x+y = c' + 2; for that to be one pixel INSIDE the ring's
     diagonal (x+y = c) it must equal c + sqrt(2), so c' = c + sqrt(2) - 2.
     The old constant subtracted 2 + sqrt(2) instead, which put the face
     diagonal one pixel OUTSIDE the ring — measured at 4x, every chamfer on
     these four pages had a lit top edge and no edge at all on the cut. */
  --sc-cut-in-adj:  0.586px;

  /* -- spacing: 4 8 12 16 24 32 48, and no value off it ------------------ */
  --sc-s1: 4px;  --sc-s2: 8px;  --sc-s3: 12px; --sc-s4: 16px;
  --sc-s5: 24px; --sc-s6: 32px; --sc-s7: 48px; --sc-s8: 72px;

  /* -- THE LOCKUP: one mark, one wordmark, one size, five sheets ---------
     The mark is drawn ONCE — here, as a mask — and no page's markup draws it
     at all. It was five drawings before: a nine-spoke nonagon on the entry
     pages, no mark on the data and tool pages, a circle-dot on the account
     pages, a 56px nine-spoke on the two masthead pages, and a sixth in every
     favicon. The nine-spoke cut fills in below about 28px, so the drawing
     that survives is the nonagon and its hub — the same silhouette, legible
     at 16px. The wordmark is the display face at the size and tracking the
     viewer's own console sets it in. */
  --sc-ic-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpolygon points='16,3 24.36,6.04 28.8,13.74 27.26,22.5 20.45,28.22 11.55,28.22 4.74,22.5 3.2,13.74 7.64,6.04' fill='none' stroke='%23000' stroke-width='2.2'/%3E%3Ccircle cx='16' cy='16' r='2.6' fill='%23000'/%3E%3C/svg%3E");
  --sc-mark-sz:  18px;
  --sc-fz-mark:  16px;
  --sc-ls-mark:  .26em;
  --sc-f-display: var(--font-display, 'Saira', 'Helvetica Neue', Arial, sans-serif);
  --sc-f-label:   var(--font-label,   'Saira', 'Helvetica Neue', Arial, sans-serif);
  --sc-w-display: 800;
  --sc-w-label:   600;

  /* -- type: one ladder, one set of tracking steps ----------------------- */
  --sc-mono: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
  --sc-sans: ui-sans-serif, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --sc-fz-nano:  11px;   /* the floor: nothing on these pages is smaller    */
  --sc-fz-micro: 12px;
  --sc-fz-small: 12.5px;
  --sc-fz-base:  13px;
  --sc-fz-read:  14px;
  --sc-fz-title: 18px;
  --sc-fz-svg:   10px;   /* inside a scaled diagram, so not a page size     */
  --sc-ls-xw:    .26em;
  --sc-ls-wide:  .20em;
  --sc-ls-mid:   .14em;
  --sc-ls-tight: .06em;

  /* -- motion ------------------------------------------------------------ */
  --sc-dur:      .12s;
  --sc-dur-slow: .30s;

  /* -- the assembly, composed once -------------------------------------
     --sc-lift is strata 1, 2 and 4 as one inset shadow list; --sc-face is
     stratum 3; --sc-drop is stratum 5. The cast shadow is a filter and not a
     box-shadow because every plate here is clipped to a chamfer, and a
     clip-path eats an outer box-shadow — a drop-shadow follows the cut
     corner exactly, which is what the shadow of a chamfered plate looks
     like anyway. --sc-cast is the same geometry as a box-shadow, for the
     parts that are not clipped. */
  --sc-return:
    inset 0 calc(-1 * var(--sc-edge-w)) 0 var(--sc-rim-lo),
    inset 0 calc(-2 * var(--sc-edge-w)) 0 var(--sc-under);
  --sc-lift:
    inset 0 var(--sc-edge-w) 0 var(--sc-rim-hi),
    inset 0 calc(var(--sc-edge-w) * 2) 0 var(--sc-lip),
    var(--sc-return);
  /* the same assembly with a status rail for its upper rim — a lit top still
     gets its shadowed bottom */
  --sc-lift-lit:
    inset 0 var(--sc-bar) 0 var(--sc-edge-lit),
    inset 0 calc(var(--sc-bar) + var(--sc-edge-w)) 0 var(--sc-lip),
    var(--sc-return);
  --sc-sink:
    inset 0 var(--sc-edge-w) 0 var(--sc-inset-lo),
    inset 0 calc(var(--sc-edge-w) * 3) var(--sc-s2) var(--sc-lip),
    inset 0 calc(-1 * var(--sc-edge-w)) 0 var(--sc-rim-lo);
  --sc-face:
    linear-gradient(180deg, var(--sc-plate-hi), var(--sc-plate) 58%, var(--sc-plate-lo));
  --sc-face-lit:
    linear-gradient(180deg, var(--sc-plate-lit), var(--sc-plate) 62%, var(--sc-plate-lo));
  --sc-face-well:
    linear-gradient(180deg, var(--sc-well), var(--sc-well-lo));
  --sc-drop:
    drop-shadow(0 var(--sc-cast-y1) var(--sc-cast-b1) var(--sc-cast-1))
    drop-shadow(0 var(--sc-cast-y2) var(--sc-cast-b2) var(--sc-cast-2));
  --sc-drop-sm:
    drop-shadow(0 var(--sc-cast-y1) var(--sc-cast-b1) var(--sc-cast-1))
    drop-shadow(0 var(--sc-cast-y3) var(--sc-cast-b3) var(--sc-cast-2));

  /* the two chamfer paths, built from the tokens. Top-left and bottom-right
     are cut; the other two stay square. One vocabulary, every plate. */
  --sc-cut: polygon(
    0 var(--sc-ch-lg), var(--sc-ch-lg) 0, 100% 0,
    100% calc(100% - var(--sc-ch-lg)), calc(100% - var(--sc-ch-lg)) 100%, 0 100%);
  --sc-cut-in: polygon(
    0 calc(var(--sc-ch-lg) - var(--sc-cut-in-adj)), calc(var(--sc-ch-lg) - var(--sc-cut-in-adj)) 0, 100% 0,
    100% calc(100% - var(--sc-ch-lg) + var(--sc-cut-in-adj)), calc(100% - var(--sc-ch-lg) + var(--sc-cut-in-adj)) 100%, 0 100%);
  --sc-cut-md: polygon(
    0 var(--sc-ch-md), var(--sc-ch-md) 0, 100% 0,
    100% calc(100% - var(--sc-ch-md)), calc(100% - var(--sc-ch-md)) 100%, 0 100%);
  --sc-cut-md-in: polygon(
    0 calc(var(--sc-ch-md) - var(--sc-cut-in-adj)), calc(var(--sc-ch-md) - var(--sc-cut-in-adj)) 0, 100% 0,
    100% calc(100% - var(--sc-ch-md) + var(--sc-cut-in-adj)), calc(100% - var(--sc-ch-md) + var(--sc-cut-in-adj)) 100%, 0 100%);
  --sc-cut-sm: polygon(
    0 var(--sc-ch-sm), var(--sc-ch-sm) 0, 100% 0,
    100% calc(100% - var(--sc-ch-sm)), calc(100% - var(--sc-ch-sm)) 100%, 0 100%);
  --sc-cut-sm-in: polygon(
    0 calc(var(--sc-ch-sm) - var(--sc-cut-in-adj)), calc(var(--sc-ch-sm) - var(--sc-cut-in-adj)) 0, 100% 0,
    100% calc(100% - var(--sc-ch-sm) + var(--sc-cut-in-adj)), calc(100% - var(--sc-ch-sm) + var(--sc-cut-in-adj)) 100%, 0 100%);

  /* -- the page's own scale ---------------------------------------------
     The one section allowed to differ from the other four sheets: a hub's
     column is not a material constant. Names still match. */
  --sc-fz-mega:     34px;   /* the one heading allowed to be big            */
  --sc-fz-num:      28px;   /* the readout numerals                         */
  --sc-rail-h:      42px;
  /* ONE MEASURE, ONE GUTTER, five sheets. The content column was 1360 here,
     1200 on /guide/, 1180 on the tool pages, 1160 on the data pages and 940
     on the account pages — which put the first pixel of content at 153, 233,
     236, 244 and 356 px on pages that are meant to be one object. 1280 is the
     narrowest viewport this app supports, so at 1280x720 the column is
     exactly gutter to gutter and nothing has to be decided twice. */
  --sc-page:        1280px;
  --sc-gutter:      var(--sc-s5);
  --sc-navcol:      312px;     /* the navigator rail                        */
  --sc-navcol-sm:   252px;
  --sc-aside:       236px;     /* a diagram column beside prose             */
  --sc-card-min:    272px;
  --sc-pcard-min:   380px;
  --sc-ro-min:      104px;
  --sc-auth-w:      400px;
  --sc-label-w:     128px;
  --sc-ctl-h:       30px;
  --sc-ctl-h-sm:    24px;
  --sc-limb-r:      min(52vw, 620px);
}
/* ---- END TOKENS ---- */

/* ===================================================== ground and reset === */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html { -webkit-text-size-adjust: 100%; }

/* display:flex on a component must not out-vote the attribute that hides it */
[hidden] { display: none !important; }

body {
  min-height: 100vh;
  background: var(--sc-ground);
  color: var(--sc-tx-hi);
  font: var(--sc-fz-base) / 1.6 var(--sc-sans);
  -webkit-font-smoothing: antialiased;
}

/* The sky. Two soft washes, one hard-edged limb arc and a hairline grid —
   all painted once into a fixed layer, so nothing costs anything per frame.
   No filters, no images, no request. */
body::before {
  content: ''; position: fixed; inset: 0; z-index: -2; pointer-events: none;
  background:
    radial-gradient(115% 85% at 84% -12%, var(--sc-sky-1), transparent 58%),
    radial-gradient(90% 70% at 4% 108%, var(--sc-sky-2), transparent 62%),
    var(--sc-ground);
}
body::after {
  content: ''; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(circle at 88% 4%, transparent 0 var(--sc-limb-r),
      var(--sc-limb) var(--sc-limb-r) calc(var(--sc-limb-r) + 1px), transparent calc(var(--sc-limb-r) + 2px)),
    repeating-linear-gradient(90deg, var(--sc-grid) 0 var(--sc-edge-w), transparent var(--sc-edge-w) 72px),
    radial-gradient(140% 100% at 50% 42%, transparent 40%, var(--sc-inset-lo) 100%);
}

/* ==========================================================================
   THE PLATE — ONE OBJECT, FIVE IDENTICAL COPIES
   Everything from this banner to "END PLATE" is byte-identical in page-entry,
   page-data, page-tool, page-account and pdf.css, exactly like the rail. Diff
   them; they must not drift.

   THE CORNER IS CHOSEN BY ROLE, NOT BY WHICH SHEET THE PAGE WAS BUILT IN.
   There were three vocabularies before and they mapped onto the four page
   families one for one: a flat hairline with a cyan corner tick on the data
   pages, a 4px bevelled frame with corner rivets on the tool pages, a
   45-degree chamfer with no bevel on the account pages. Same role, three
   drawings. One now, sized by the part:

     PLATE  a panel on a page — cut at the top-left and the bottom-right at
            --sc-ch-lg, square on the other two. TWO cuts and not four,
            because a plate is keyed: a stack of them reads as an assembly
            rather than a row of tickets, and a table or a chart inside one
            only has to keep two corners clear instead of four.
     CARD   a tile inside a panel or a grid — the same construction at
            --sc-ch-md, because the cut is proportional to the part.
     KEY    a control: button, field, tag. --sc-ch-sm, all four corners,
            because a part that small has no orientation worth keying.

   WHAT IS ALLOWED TO DIFFER, and why it is a role and not an accident: the
   viewer's HUD and /pdf/'s dock FRAME are machined parts clamped over a live
   3D scene, not surfaces on a page. They keep the heavier bevel, because they
   have to hold their own silhouette against whatever colour the world behind
   them happens to be that second, and a page never has to. The panels INSIDE
   that dock are page content and are plates like everything else.

   HOW IT IS BUILT, and why the cut is not on the element. A clip-path is
   applied to the FILTERED result, so a drop-shadow on a clipped element is
   clipped away — measured, and it is why chamfered plates used to have one
   stroke and no shadow. With the cut on the pseudo layers the element itself
   stays unclipped and its drop-shadow follows the silhouette of the clipped
   layers beneath: the chamfered outline, corners and all. No outer box-shadow
   can draw that. The edge colour travels in --sc-ring rather than in
   `background`, because the element's own background paints beneath both
   layers and would show square corners outside the cut.
   ========================================================================== */

.sc-plate, .plate, .sc-panel, .panel, .card {
  position: relative;
  isolation: isolate;
  border: 0;
  border-radius: 0;
  background: none;
  --sc-ring: var(--sc-edge);
  filter: var(--sc-drop);                       /* stratum 5, the cast */
}
.sc-plate::after, .plate::after, .sc-panel::after, .panel::after, .card::after {
  content: ''; position: absolute; inset: 0; z-index: -2; pointer-events: none;
  clip-path: var(--sc-cut);
  background: var(--sc-ring);
  transition: background var(--sc-dur);
}
.sc-plate::before, .plate::before, .sc-panel::before, .panel::before, .card::before {
  content: ''; position: absolute; inset: var(--sc-edge-w); z-index: -1; pointer-events: none;
  clip-path: var(--sc-cut-in);
  background: var(--sc-face);                   /* stratum 3, the face   */
  box-shadow: var(--sc-lift);                   /* strata 1, 2 and 4     */
}
.sc-plate > *, .plate > *, .sc-panel > *, .panel > *, .card > * { position: relative; z-index: 1; }

/* CARD — the same plate, one step down the cut ladder */
.sc-card, .plate--sm { filter: var(--sc-drop-sm); }
.sc-card::after,  .plate--sm::after  { clip-path: var(--sc-cut-md); }
.sc-card::before, .plate--sm::before { clip-path: var(--sc-cut-md-in); }

/* the smallest plate there is — a chip, a readout tag */
.plate--xs::after  { clip-path: var(--sc-cut-sm); }
.plate--xs::before { clip-path: var(--sc-cut-sm-in); }

/* a recessed well rather than a raised face: the rim order inverts — dark
   above, light on the way back out — and it casts nothing, because it is a
   hole rather than a plate */
.plate--well, .sc-well { filter: none; }
.plate--well::before, .sc-well::before {
  background: var(--sc-face-well);
  box-shadow: var(--sc-sink);
}
/* --------------------------------------------------------------- END PLATE */

/* ==========================================================================
   THE RAIL — ONE OBJECT, FIVE IDENTICAL COPIES
   Everything from this banner to "END RAIL" is byte-identical in page-entry,
   page-data, page-tool, page-account and pdf.css. Diff them; they must not
   drift. Change one, change five, or the app is four families again.

   THE LOCKUP is drawn ONCE, in --sc-ic-mark, as a mask — so there is no SVG
   in any page's markup and no second drawing to fall out of step. It was
   five drawings before: a nine-spoke nonagon on the entry pages, no mark at
   all on the data and tool pages, a circle-dot on the account pages, and a
   56px nine-spoke on the two masthead pages. The nine-spoke cut is genuinely
   illegible at rail size — measured at 5x, the spokes fill in and it reads as
   a filled blob — so the mark that survives is the nonagon and its hub, which
   is the same silhouette the product is named for and holds down to 16px.

   THE WORDMARK is the display face at --sc-fz-mark/--sc-ls-mark, which is
   what the viewer's own console sets it in. It used to be four typefaces
   across the app: SF Mono on the entry and data pages, real Saira on the
   account pages, and — by accident, because those pages never loaded the
   type layer — Helvetica Neue on the tool pages. Every page now links
   /vendor/fonts/fonts.css, so the fallback is a fallback again.

   THE BEAM IS BOLTED TO THE WINDOW, NOT TO THE PAGE COLUMN. Its parts sit at
   --sc-s4 from the window edge on every page, the same inset the viewer's
   identity plate uses. The data pages used to indent theirs to the content
   column instead (220px at 1600), which made the same rail look like two
   rails side by side. The rail belongs to the application; the column belongs
   to the page.

   SOUND HAS ONE HOME: the socket at the right end, beside the account. It is
   mounted by markup — <span class="sfx" data-sfx-mount="mute"> — which the
   engine fills on discovery, and which stands the engine's own bottom-left
   fallback dock down. That dock was a floating widget with nothing under it:
   at 1280x720 on /lifecycle/ it sat on top of the PROJECT CONTROLS nav item
   and covered five letters of a live link. A control that occludes navigation
   is a bug at any size, and the cure is a reserved seat, not a nudge.
   ========================================================================== */

#top {
  position: sticky; top: 0; z-index: 40;
  box-sizing: border-box;
  width: 100%; max-width: none; height: var(--sc-rail-h); flex: none;
  display: flex; align-items: center; gap: 0;
  padding: 0 var(--sc-s4);
  background: var(--sc-metal-short), var(--sc-st-3);
  font: var(--sc-w-label) var(--sc-fz-micro)/1 var(--sc-f-label);
  letter-spacing: var(--sc-ls-mid);
  /* 1 rim · 2 lip · 4 return · 5 cast */
  box-shadow:
    inset 0 var(--sc-edge-w) 0 var(--sc-rim-hi),
    inset 0 calc(var(--sc-edge-w) * 2) 0 var(--sc-lip),
    inset 0 calc(-1 * var(--sc-edge-w)) 0 var(--sc-bevel-lo),
    0 var(--sc-edge-w) 0 var(--sc-cast-1),
    0 var(--sc-cast-y2) 20px var(--sc-cast-2);
}
#top::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, var(--sc-warm-rim), transparent 16px),
              var(--sc-brushed);
}
#top > * { position: relative; z-index: 2; }

/* the brand bay: a socket milled into the beam, lit from underneath.
   The right padding pays back the wordmark's tracking, which would otherwise
   leave --sc-ls-mark of air after the D and push the lockup off centre. */
#top .brand {
  display: flex; align-items: center; gap: var(--sc-s2);
  align-self: center; height: 26px;
  padding: 0 calc(var(--sc-s3) - var(--sc-ls-mark)) 0 var(--sc-s3);
  text-decoration: none; white-space: nowrap;
  font: var(--sc-w-display) var(--sc-fz-mark)/1 var(--sc-f-display);
  font-stretch: 112.5%; letter-spacing: var(--sc-ls-mark);
  color: var(--sc-cy); text-shadow: 0 0 10px var(--sc-cy-glow);
  background: var(--sc-socket-lit);
  box-shadow: inset 0 0 0 var(--sc-edge-w) var(--sc-cy-line),
              inset 0 calc(-1 * var(--sc-bar)) 0 var(--sc-cy),
              inset 0 3px 8px var(--sc-shadow);
  clip-path: polygon(var(--sc-ch-sm) 0, 100% 0, 100% calc(100% - var(--sc-ch-sm)),
                     calc(100% - var(--sc-ch-sm)) 100%, 0 100%, 0 var(--sc-ch-sm));
}
#top .brand:hover { color: var(--sc-tx-hi); }
/* the bay is cut, and a clip-path eats an outline; it also already wears a
   cyan rim, so a cyan ring would be cyan on cyan */
#top .brand:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 var(--sc-focus-w) var(--sc-tx-hi), inset 0 3px 8px var(--sc-shadow);
}
/* the mark: one drawing, in one token, masked so it tints with the bay's ink */
#top .mark {
  flex: none; display: block;
  width: var(--sc-mark-sz); height: var(--sc-mark-sz);
  background: currentColor;
  -webkit-mask: var(--sc-ic-mark) center / contain no-repeat;
          mask: var(--sc-ic-mark) center / contain no-repeat;
}

/* the separator is a milled notch, not a middot */
#top .sep {
  flex: none; align-self: center;
  width: var(--sc-edge-w); height: 18px; margin: 0 var(--sc-s3);
  font-size: 0; color: transparent; overflow: hidden;
  background: linear-gradient(180deg, transparent, var(--sc-st-1), transparent);
  box-shadow: var(--sc-edge-w) 0 0 var(--sc-glass);
}
#top .page {
  /* display:block, not flex. `text-overflow: ellipsis` applies to the inline
     content of a BLOCK container and does nothing at all on a flex container —
     so this rule looked like it handled a long title and never did: at 390px
     "LEGACY PDF TO BIM" hard-clipped to "LEGACY PDF TO BI" under the sound
     socket, with no ellipsis to tell the reader anything was missing. The box
     is still a flex ITEM of #top, so align-self keeps centring it; the line-
     height does the vertical centring the inner flex used to do. */
  display: block; line-height: var(--sc-rail-h); align-self: center;
  min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font: var(--sc-w-label) var(--sc-fz-micro)/1 var(--sc-f-label);
  letter-spacing: var(--sc-ls-wide); text-transform: uppercase;
  color: var(--sc-tx-hi); text-shadow: 0 1px 0 var(--sc-tx-sh);
}
/* the nav is divided by the same milled notch, never by a drawn border */
#top .nav { display: flex; align-items: stretch; align-self: stretch; margin-left: var(--sc-s3); }
#top .nav a {
  position: relative;
  display: flex; align-items: center; padding: 0 var(--sc-s4);
  color: var(--sc-tx-hi); text-decoration: none;
  text-shadow: 0 1px 0 var(--sc-tx-sh);
  font: var(--sc-w-label) var(--sc-fz-micro)/1 var(--sc-f-label);
  letter-spacing: var(--sc-ls-mid); text-transform: uppercase;
  transition: color var(--sc-dur);
}
#top .nav a::before {
  content: ''; position: absolute; left: 0; top: 50%; margin-top: -9px;
  width: var(--sc-edge-w); height: 18px;
  background: linear-gradient(180deg, transparent, var(--sc-st-1), transparent);
  box-shadow: var(--sc-edge-w) 0 0 var(--sc-glass);
}
#top .nav a:hover { color: var(--sc-cy); text-shadow: 0 0 10px var(--sc-cy-glow); }

/* THE RIGHT END. One socket, balancing the brand bay: the account reads in
   it, and SOUND is the key seated at its end. Nothing dim survives printed
   straight onto lit metal, which is why both live in a recess. */
#top .rail-end {
  margin-left: auto; align-self: center;
  display: flex; align-items: center; height: var(--sc-ctl-h-sm);
  background: var(--sc-socket);
  box-shadow: inset 0 0 0 var(--sc-edge-w) var(--sc-seat), inset 0 2px 6px var(--sc-shadow);
  clip-path: polygon(var(--sc-ch-sm) 0, 100% 0, 100% 100%,
                     var(--sc-ch-sm) 100%, 0 calc(100% - var(--sc-ch-sm)), 0 var(--sc-ch-sm));
}
#top #who {
  display: flex; align-items: center; height: 100%; padding: 0 var(--sc-s3);
  max-width: 34ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font: var(--sc-w-label) var(--sc-fz-nano)/1 var(--sc-f-label);
  letter-spacing: var(--sc-ls-mid); color: var(--sc-tx-dim);
}
#top #who:empty { display: none; }
#top #who a { color: var(--sc-tx-hi); }
#top #who a:hover { color: var(--sc-cy); }
#top .sfx { display: flex; align-items: center; height: 100%; }
/* the notch only exists when there is something on both sides of it */
#top #who:not(:empty) + .sfx::before {
  content: ''; flex: none; width: var(--sc-edge-w); height: 14px;
  background: linear-gradient(180deg, transparent, var(--sc-st-1), transparent);
  box-shadow: var(--sc-edge-w) 0 0 var(--sc-glass);
}
/* THE SOUND KEY, seated in the socket. Styled HERE and not by the sound
   engine's own injected stylesheet, because this rail asks the ENGINE to fill
   a markup mount point (data-sfx-mount) rather than letting the wire mount the
   control — and sfx-wire's mountMute() returns early when it finds a .sfx-mute
   already present, BEFORE it appends its <style>. The key then rendered as a
   raw UA button, black on ButtonFace, on whichever pages lost that race. A
   control seated in this socket is the socket's business anyway; the engine's
   own comment says a HUD-mounted one is never restyled behind the HUD's back.
   Its focus style there was one step of near-white, measured at 1.16:1,
   which is not an indicator. It rings. */
#top .sfx .sfx-mute {
  appearance: none; -webkit-appearance: none;
  display: flex; align-items: center; height: 100%;
  padding: 0 var(--sc-s3);
  border: 0; border-radius: 0; background: none; cursor: pointer;
  font: var(--sc-w-label) var(--sc-fz-nano)/1 var(--sc-f-label);
  letter-spacing: var(--sc-ls-mid); text-transform: uppercase; white-space: nowrap;
  color: var(--sc-tx-hi);
  transition: color var(--sc-dur);
}
#top .sfx .sfx-mute:hover { color: var(--sc-cy); }
/* off is a glyph and an aria-pressed, not a fade: one rung of ink at most, and
   it still clears AA on the socket */
#top .sfx .sfx-mute.muted { color: var(--sc-tx-dim); }
#top .sfx .sfx-mute:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 var(--sc-bar) var(--sc-cy);
}

@media (max-width: 860px) {
  #top .nav a { padding: 0 var(--sc-s3); }
}
@media (max-width: 640px) {
  #top { padding: 0 var(--sc-s3); }
  #top .nav, #top #who { display: none; }
  #top .sep { margin: 0 var(--sc-s2); }
}
/* ---------------------------------------------------------------- END RAIL */

/* ================================================================ the shell === */
.shell {
  width: 100%; max-width: var(--sc-page); margin: 0 auto;
  padding: var(--sc-s5) var(--sc-gutter) var(--sc-s6);
  min-height: calc(100vh - var(--sc-rail-h));
  display: flex; flex-direction: column;
}

/* the masthead: a big quiet title, one sentence, and the readouts on the right */
.mast {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sc-s7); align-items: end;
  margin-bottom: var(--sc-s3);
}
.mast h1 {
  font: 300 var(--sc-fz-mega) / 1.12 var(--sc-mono);
  letter-spacing: var(--sc-ls-wide); color: var(--sc-tx-hi);
  text-transform: uppercase;
}
.mast h1 b { font-weight: 700; color: var(--sc-tx-max); }
.mast h1 i { font-style: normal; color: var(--sc-cy-2); }
.mast .lede {
  margin-top: var(--sc-s4); max-width: 62ch;
  color: var(--sc-tx); font-size: var(--sc-fz-read); line-height: 1.65;
}
/* the page's first line, so it is held to the ink floor and not to the edge
   colour it used to borrow — that measured 4.37:1 over the sky wash */
.mast .kicker {
  display: block; margin-bottom: var(--sc-s3);
  color: var(--sc-cy-ink); font: var(--sc-fz-micro) / 1 var(--sc-mono);
  letter-spacing: var(--sc-ls-xw); text-transform: uppercase;
}

.cta { display: flex; flex-wrap: wrap; gap: var(--sc-s3); margin-top: var(--sc-s5); }

/* the signature seam: one lit hairline fading out, one dark line under it */
.hr {
  height: var(--sc-edge-w); border: 0; margin: var(--sc-s4) 0 var(--sc-s4);
  background: linear-gradient(90deg, var(--sc-edge-lit), var(--sc-edge) 38%, transparent 92%);
  box-shadow: 0 var(--sc-edge-w) 0 var(--sc-bevel-lo);
}

/* ================================================================ readouts === */
.readouts { display: flex; align-items: stretch; }
/* The instrument readout used to be a 2px lit rail on top of a wash that
   stepped straight out to the page background at the bottom — a lit top with
   no shadowed bottom, which reads as a fade rather than a plate. The rail is
   now stratum 1 of the assembly, so it arrives with the dark lip under it,
   the return at the bottom and the cast shadow beneath. */
.readouts.instr {
  padding: var(--sc-s3) var(--sc-s5) var(--sc-s4);
}
.readouts.instr::before {
  background:
    linear-gradient(180deg, var(--sc-cy-wash), transparent 70%),
    var(--sc-face);
  box-shadow: var(--sc-lift-lit);
}
.ro {
  min-width: var(--sc-ro-min); padding: 0 var(--sc-s4);
  text-align: right;
}
.ro + .ro { border-left: var(--sc-edge-w) solid var(--sc-edge); }
.ro:last-child { padding-right: 0; }
.ro b {
  display: block; font: 300 var(--sc-fz-num) / 1 var(--sc-mono); letter-spacing: var(--sc-ls-tight);
  color: var(--sc-tx-hi);
}
.ro span {
  display: block; margin-top: var(--sc-s2);
  font: var(--sc-fz-nano) / 1 var(--sc-mono); letter-spacing: var(--sc-ls-wide);
  color: var(--sc-tx-dim);
}
/* a readout whose value is a word, not a number, keeps the label's scale */
.ro--word b { font-size: var(--sc-fz-title); line-height: var(--sc-fz-num); letter-spacing: var(--sc-ls-mid); }
.ro--live b { color: var(--sc-gn); }
.ro--plan b { color: var(--sc-tx-dim); }
.ro--warm b { color: var(--sc-am); }

/* ================================================================= buttons === */
.btn {
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; gap: var(--sc-s2);
  min-height: var(--sc-ctl-h);
  padding: var(--sc-s3) var(--sc-s5); border: 0;
  --sc-ring: var(--sc-edge-lit);
  color: var(--sc-cy); text-decoration: none; cursor: pointer;
  font: var(--sc-fz-micro) / 1.2 var(--sc-mono); letter-spacing: var(--sc-ls-wide);
  text-transform: uppercase;
  filter: var(--sc-drop-sm);
  transition: color var(--sc-dur);
}
/* a key gets the same five strata as a plate, at the small part's cast — and
   --sc-ch-sm, which is the cut every key on every other page wears */
.btn::after {
  content: ''; position: absolute; inset: 0; z-index: -2;
  clip-path: var(--sc-cut-sm);
  background: var(--sc-ring);
  transition: background var(--sc-dur);
}
.btn::before {
  content: ''; position: absolute; inset: var(--sc-edge-w); z-index: -1;
  clip-path: var(--sc-cut-sm-in);
  background: var(--sc-face);
  box-shadow: var(--sc-lift);
  transition: background var(--sc-dur);
}
.btn:hover { --sc-ring: var(--sc-cy); }
.btn:hover::before {
  background: var(--sc-face-lit);
  box-shadow: var(--sc-lift), inset 0 0 var(--sc-s5) var(--sc-cy-wash);
}
/* the primary: warm, and there is at most one on a screen */
.btn--primary { --sc-ring: var(--sc-am); color: var(--sc-am); }
.btn--primary::before { box-shadow: var(--sc-lift), inset 0 0 var(--sc-s5) var(--sc-am-wash); }
.btn--primary:hover { --sc-ring: var(--sc-am-hi); color: var(--sc-am-tx); }
.btn--primary:hover::before { box-shadow: var(--sc-lift), inset 0 0 var(--sc-s6) var(--sc-am-wash-2); }
/* the quiet one */
.btn--ghost { --sc-ring: var(--sc-edge); color: var(--sc-tx); }
.btn--ghost:hover { --sc-ring: var(--sc-edge-lit); color: var(--sc-tx-hi); }
.btn--ghost:hover::before { box-shadow: var(--sc-lift); }
.btn--sm { padding: var(--sc-s2) var(--sc-s3); font-size: var(--sc-fz-nano); min-height: 0; }
.btn--block { width: 100%; justify-content: center; padding: var(--sc-s4) var(--sc-s5); }
/* a disabled key is not raised, so it neither catches light nor casts */
.btn:disabled { --sc-ring: var(--sc-edge-soft); color: var(--sc-tx-off); cursor: default; filter: none; }
.btn:disabled::before { box-shadow: inset 0 var(--sc-edge-w) 0 var(--sc-lip); }

/* ============================================================== the console === */
/* one frame: a navigator rail on the left, the open bay on the right */
.console {
  display: grid; grid-template-columns: var(--sc-navcol) minmax(0, 1fr);
}
/* the index tab on the console's top edge. It hangs off .nav-col, not off
   .console, because .console is a .plate and a plate's ::after is now its
   structural edge — see the note on .plate. .nav-col starts at the console's
   own left edge, so the mark lands in exactly the same place. */
.nav-col::before {
  content: ''; position: absolute; top: 0; left: var(--sc-ch-lg);
  width: var(--sc-s8); height: var(--sc-bar); background: var(--sc-cy-2);
}
.nav-col { position: relative; padding: var(--sc-s4) var(--sc-s5) var(--sc-s5); }
.nav-col #nonagon { max-width: 208px; margin: 0 auto; }
/* the seam, fading at both ends so it reads as machined rather than drawn */
.nav-col::after {
  content: ''; position: absolute; top: var(--sc-s5); bottom: var(--sc-s5);
  right: 0; width: var(--sc-edge-w);
  background: linear-gradient(180deg, transparent, var(--sc-edge) 10%, var(--sc-edge) 90%, transparent);
}
.bay-col { padding: var(--sc-s5) var(--sc-s6); min-width: 0; }

/* ================================================================= nonagon === */
#nonagon { width: 100%; height: auto; display: block; }
#nonagon .ring { fill: none; stroke: var(--sc-edge); stroke-width: 1.2; }
#nonagon .spoke { stroke: var(--sc-edge-soft); stroke-width: 1; fill: none; }
#nonagon .spoke.on { stroke: var(--sc-cy-2); }
#nonagon .pip { fill: var(--sc-cy); opacity: .55; }
#nonagon .v { cursor: pointer; }
#nonagon .v .well { fill: var(--sc-well); stroke: var(--sc-edge-lit); stroke-width: 1.2; transition: stroke var(--sc-dur); }
#nonagon .v .mark { fill: var(--sc-edge-lit); transition: fill var(--sc-dur); }
#nonagon .v.live .well { stroke: var(--sc-cy-2); }
#nonagon .v.live .mark { fill: var(--sc-cy); opacity: .75; }
#nonagon .v .halo { fill: none; stroke: var(--sc-cy); stroke-width: 1; opacity: 0; transition: opacity var(--sc-dur); }
#nonagon .v:hover .well, #nonagon .v:focus-visible .well { stroke: var(--sc-cy); }
#nonagon .v:hover .mark, #nonagon .v:focus-visible .mark { fill: var(--sc-cy); }
#nonagon .v:focus-visible .halo { opacity: 1; }
#nonagon .v.on .well { fill: var(--sc-cy); stroke: var(--sc-cy); }
#nonagon .v.on .mark { fill: var(--sc-ground); }
#nonagon .v.on .halo { opacity: .5; }
#nonagon .core { fill: none; stroke: var(--sc-cy-2); stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round; }
#nonagon .core .dot { fill: var(--sc-cy-2); stroke: none; }

/* ============================================================ navigator rail === */
.stagenav { display: flex; flex-direction: column; margin-top: var(--sc-s4); }
.stagenav button {
  position: relative; display: flex; align-items: center; gap: var(--sc-s3);
  width: 100%; padding: var(--sc-s1) var(--sc-s3) var(--sc-s1) var(--sc-s4);
  background: none; border: 0; border-left: var(--sc-bar) solid transparent; cursor: pointer;
  color: var(--sc-tx-dim); text-align: left;
  /* the nine stage names ARE the hub's navigation; they were the smallest
     type on the page. Bigger than every label around them, and the tracking
     comes back in so the longest name still holds one line in the rail. */
  font: var(--sc-fz-base) / 1.5 var(--sc-mono); letter-spacing: var(--sc-ls-tight);
  transition: color var(--sc-dur), background var(--sc-dur), border-color var(--sc-dur);
}
.stagenav button + button { box-shadow: inset 0 var(--sc-edge-w) 0 var(--sc-edge-soft); }
.stagenav button::before {
  content: ''; width: var(--sc-s1); height: var(--sc-s1); flex: none; border-radius: var(--sc-radius);
  background: var(--sc-tx-off); transition: background var(--sc-dur), box-shadow var(--sc-dur);
}
.stagenav button.has-live::before { background: var(--sc-cy-2); }
.stagenav button:hover { color: var(--sc-tx-hi); background: var(--sc-sheen); }
.stagenav button.on {
  color: var(--sc-tx-hi); background: var(--sc-cy-wash); border-left-color: var(--sc-cy);
}
.stagenav button.on::before { background: var(--sc-cy); box-shadow: 0 0 6px var(--sc-cy); }

/* the legend, under the badges it explains rather than off in the rail */
.legend {
  margin-top: var(--sc-s4); padding-top: var(--sc-s3);
  border-top: var(--sc-edge-w) solid var(--sc-edge-soft);
  /* a full sentence, not a label, so it takes the body step and not the floor */
  color: var(--sc-tx-dim); font: var(--sc-fz-micro) / 1.8 var(--sc-mono);
  letter-spacing: var(--sc-ls-tight);
}
.legend b { color: var(--sc-gn); font-weight: 400; }
.legend i { font-style: normal; color: var(--sc-tx-off); }

/* ==================================================================== bay === */
section.stage[hidden] { display: none; }
section.stage h2 {
  font: 400 var(--sc-fz-title) / 1.2 var(--sc-mono); letter-spacing: var(--sc-ls-wide);
  color: var(--sc-tx-hi);
}
section.stage .tagline {
  margin: var(--sc-s3) 0 var(--sc-s4); max-width: 70ch;
  color: var(--sc-tx-dim); font-size: var(--sc-fz-small);
}
/* the seam belongs to the bay, so it runs the bay's full width — hung off the
   tagline it stopped wherever that sentence happened to end */
section.stage .cards {
  padding-top: var(--sc-s4);
  border-top: var(--sc-edge-w) solid var(--sc-edge-soft);
}
/* a stage with one feature gets a card with presence rather than a chip
   stranded in a three-column grid */
.cards > .fcard:only-child { grid-column: span 2; }
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--sc-card-min), 1fr)); gap: var(--sc-s3); }

.fcard {
  display: block; padding: var(--sc-s4) var(--sc-s4) var(--sc-s5);
  text-decoration: none; color: inherit;
  transition: background var(--sc-dur);
}
.fcard .badge {
  display: inline-block; margin-bottom: var(--sc-s3);
  font: var(--sc-fz-nano) / 1 var(--sc-mono); letter-spacing: var(--sc-ls-wide);
  color: var(--sc-tx-dim);
}
.fcard.live .badge { color: var(--sc-gn); }
.fcard.built .badge { color: var(--sc-am); }
.fcard b {
  display: block; margin-bottom: var(--sc-s2);
  font: 600 var(--sc-fz-base) / 1.35 var(--sc-sans); letter-spacing: var(--sc-ls-tight);
  color: var(--sc-tx-hi);
}
.fcard p { color: var(--sc-tx-dim); font-size: var(--sc-fz-small); line-height: 1.6; }

/* PLANNED is not a link and must not look like one: no lit edge, a hatched
   left margin instead, and ink held back. */
.fcard.plan { --sc-ring: var(--sc-edge-soft); filter: none; }
.fcard.plan::before {
  background:
    repeating-linear-gradient(135deg, var(--sc-hatch) 0 var(--sc-edge-w), transparent var(--sc-edge-w) var(--sc-hatch-pitch)),
    var(--sc-face-well);
  box-shadow: var(--sc-sink);
}
.fcard.plan b { color: var(--sc-tx); }
/* Held back by the hatch field, the hollow dot, the dimmed badge and by not
   being a link — four channels — rather than by ink below the contrast floor.
   This description measured 2.71:1 over that hatch. */
.fcard.plan p { color: var(--sc-tx-dim); }

a.fcard { --sc-ring: var(--sc-edge); }
/* the "opens something" mark. It hangs off the title rather than off the card,
   because a plate's ::after is now its structural edge — see .plate. */
a.fcard b::after {
  content: '↗'; position: absolute; top: var(--sc-s3); right: var(--sc-s4);
  color: var(--sc-cy); font: var(--sc-fz-micro) / 1 var(--sc-mono);
  opacity: 0; transition: opacity var(--sc-dur);
}
a.fcard:hover, a.fcard:focus-visible { --sc-ring: var(--sc-cy-2); }
a.fcard:hover::before, a.fcard:focus-visible::before { background: var(--sc-face-lit); }
a.fcard:hover b::after, a.fcard:focus-visible b::after { opacity: 1; }

/* ================================================================= the index === */
.index {
  margin-top: auto; padding-top: var(--sc-s4);
  border-top: var(--sc-edge-w) solid var(--sc-edge-soft);
  display: grid; grid-template-columns: var(--sc-label-w) minmax(0, 1fr); gap: var(--sc-s4);
  align-items: baseline;
}
/* measured 2.78:1 — a label nobody can read is not a quiet label */
.index > span {
  color: var(--sc-tx-dim); font: var(--sc-fz-nano) / 1.8 var(--sc-mono);
  letter-spacing: var(--sc-ls-wide);
}
.index nav { display: flex; flex-wrap: wrap; gap: var(--sc-s2) var(--sc-s5); padding-top: var(--sc-s4); }
.index a {
  color: var(--sc-tx-dim); text-decoration: none;
  font: var(--sc-fz-nano) / 1.8 var(--sc-mono); letter-spacing: var(--sc-ls-mid);
  transition: color var(--sc-dur);
}
.index a:hover { color: var(--sc-cy); }
.index button {
  margin-left: auto; background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--sc-tx-dim); font: var(--sc-fz-nano) / 1.8 var(--sc-mono);
  letter-spacing: var(--sc-ls-mid);
}
.index button:hover { color: var(--sc-rd); }

/* ============================================================ /projects/ ===== */
.pg-projects .plist {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--sc-pcard-min), 1fr)); gap: var(--sc-s3);
}
.pcard {
  display: block; min-height: calc(var(--sc-s8) * 2); padding: var(--sc-s4) var(--sc-s5) var(--sc-s5);
  text-decoration: none; color: inherit; --sc-ring: var(--sc-edge-soft);
}
a.pcard { --sc-ring: var(--sc-edge); }
/* bottom-right, because the status tag already owns the card's top-right.
   Hung off .nm rather than the card, because a plate's ::after is now its
   structural edge; absolutely positioned, so it is not a flex item of .nm. */
a.pcard .nm::after {
  content: '↗'; position: absolute; bottom: var(--sc-s3); right: var(--sc-s4);
  color: var(--sc-cy); font: var(--sc-fz-micro) / 1 var(--sc-mono);
  opacity: 0; transition: opacity var(--sc-dur);
}
a.pcard:hover, a.pcard:focus-visible { --sc-ring: var(--sc-cy-2); }
a.pcard:hover .nm::after, a.pcard:focus-visible .nm::after { opacity: 1; }
a.pcard:hover::before, a.pcard:focus-visible::before { background: var(--sc-face-lit); }
.pcard .nm {
  display: flex; align-items: center; gap: var(--sc-s3);
  margin-bottom: var(--sc-s3); padding-bottom: var(--sc-s3);
  border-bottom: var(--sc-edge-w) solid var(--sc-edge-soft);
  font: 600 var(--sc-fz-read) / 1.3 var(--sc-mono); letter-spacing: var(--sc-ls-tight);
  color: var(--sc-tx-hi);
}
.pcard .tag {
  margin-left: auto; flex: none; padding: var(--sc-s1) var(--sc-s2); border-radius: var(--sc-radius);
  border: var(--sc-edge-w) solid var(--sc-edge); color: var(--sc-tx-dim);
  font: var(--sc-fz-nano) / 1.4 var(--sc-mono); letter-spacing: var(--sc-ls-mid);
}
.pcard .tag.on { color: var(--sc-gn); border-color: var(--sc-gn-edge); }
.pcard .tag.demo { color: var(--sc-cy); border-color: var(--sc-edge-lit); }
.pcard .sub { color: var(--sc-tx-dim); font-size: var(--sc-fz-small); line-height: 1.65; }
.pcard .id {
  margin-top: var(--sc-s3); color: var(--sc-tx-off);
  font: var(--sc-fz-nano) / 1.4 var(--sc-mono); letter-spacing: var(--sc-ls-tight);
}
.pcard.muted { opacity: .7; }
.empty {
  grid-column: 1 / -1; padding: var(--sc-s6) var(--sc-s6) var(--sc-s7);
  --sc-ring: var(--sc-edge-soft); filter: none;
}
.empty::before {
  background:
    repeating-linear-gradient(135deg, var(--sc-hatch) 0 var(--sc-edge-w), transparent var(--sc-edge-w) var(--sc-hatch-pitch)),
    var(--sc-face-well);
  box-shadow: var(--sc-sink);
}
.empty b { display: block; margin-bottom: var(--sc-s2); color: var(--sc-tx-hi); font-weight: 600; }
.empty p { color: var(--sc-tx-dim); font-size: var(--sc-fz-small); max-width: 56ch; }
.empty .btn { margin-top: var(--sc-s5); }

/* =============================================================== /login/ ===== */
/* The sign-in screen carries the same rail as every other page and no second
   drawing of the mark: the lockup is up there, once. What is left here is the
   page's masthead — a wordmark and one line — set in the same display face
   and the same tracking as the rail's, so the two read as one identity
   rather than two logos. */
.pg-login { display: flex; flex-direction: column; min-height: 100vh; }
.auth {
  width: 100%; max-width: var(--sc-auth-w); margin: auto;
  padding: var(--sc-s7) var(--sc-gutter) var(--sc-s8);
}
.auth-brand { text-align: center; margin-bottom: var(--sc-s7); }
.auth-brand h1 {
  font: var(--sc-w-display) var(--sc-fz-title) / 1 var(--sc-f-display);
  font-stretch: 112.5%; letter-spacing: var(--sc-ls-mark);
  color: var(--sc-tx-hi);
}
.auth-brand p {
  margin-top: var(--sc-s3); color: var(--sc-tx-dim);
  font: var(--sc-fz-nano) / 1.6 var(--sc-mono); letter-spacing: var(--sc-ls-wide);
  text-transform: uppercase;
}
.authcard { padding: var(--sc-s5) var(--sc-s5) var(--sc-s5); }
.authcard .head {
  padding-bottom: var(--sc-s3); margin-bottom: var(--sc-s4);
  border-bottom: var(--sc-edge-w) solid var(--sc-edge);
  color: var(--sc-cy); font: var(--sc-fz-micro) / 1 var(--sc-mono);
  letter-spacing: var(--sc-ls-wide);
}
.authcard .note { color: var(--sc-tx-dim); font-size: var(--sc-fz-small); line-height: 1.65; }
.invited {
  padding: var(--sc-s3) var(--sc-s3); background: var(--sc-well);
  border: var(--sc-edge-w) solid var(--sc-edge); color: var(--sc-cy);
  font: var(--sc-fz-small) / 1.4 var(--sc-mono); word-break: break-all;
}
.auth-out {
  margin-top: var(--sc-s4); text-align: center;
  font: var(--sc-fz-nano) / 1.6 var(--sc-mono); letter-spacing: var(--sc-ls-mid);
}
.auth-out a { color: var(--sc-tx-dim); text-decoration: none; }
.auth-out a:hover { color: var(--sc-cy); }
.err { min-height: 20px; margin-top: var(--sc-s3); color: var(--sc-rd); font-size: var(--sc-fz-small); }

/* fields, shared by every form on these pages */
label {
  display: block; margin: var(--sc-s4) 0 var(--sc-s2);
  color: var(--sc-tx-dim); font: var(--sc-fz-nano) / 1 var(--sc-mono);
  letter-spacing: var(--sc-ls-wide);
}
input[type=text], input[type=email], input[type=password] {
  width: 100%; padding: var(--sc-s3); outline: none;
  background: var(--sc-well); color: var(--sc-tx-hi);
  border: var(--sc-edge-w) solid var(--sc-edge);
  box-shadow: inset 0 var(--sc-edge-w) 0 var(--sc-inset-lo);
  font: var(--sc-fz-base) / 1.4 var(--sc-mono);
  transition: border-color var(--sc-dur);
}
input:focus { border-color: var(--sc-cy); }
input::placeholder { color: var(--sc-tx-off); }

/* ================================================================ /guide/ ==== */
/* /guide/ used to hold its own column width, 1200 against the hub's 1360, and
   the two landed 79px apart on the same rail. One measure now; the reading
   width is set on the prose itself, where it belongs, not on the page. */

/* the phase rail */
.pg-guide .phases { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: var(--sc-edge-w); }
.pg-guide .phase {
  padding: var(--sc-s2) 0 var(--sc-s3);
  border-bottom: var(--sc-bar) solid var(--sc-edge);
  color: var(--sc-tx-off); font: var(--sc-fz-nano) / 1 var(--sc-mono);
  letter-spacing: var(--sc-ls-wide);
  transition: color var(--sc-dur-slow), border-color var(--sc-dur-slow);
}
.pg-guide .phase.done { color: var(--sc-tx-dim); border-bottom-color: var(--sc-edge-lit); }
.pg-guide .phase.on { color: var(--sc-cy); border-bottom-color: var(--sc-cy); }

/* the step chips */
.pg-guide .chips { display: flex; flex-wrap: wrap; gap: var(--sc-s2); margin-top: var(--sc-s4); }
.pg-guide .chip {
  position: relative; isolation: isolate;
  width: var(--sc-ctl-h); height: var(--sc-ctl-h); padding: 0; border: 0; cursor: pointer;
  display: grid; place-items: center;
  --sc-ring: var(--sc-edge);
  color: var(--sc-tx-dim); font: var(--sc-fz-micro) / 1 var(--sc-mono);
  filter: var(--sc-drop-sm);
  transition: color var(--sc-dur);
}
.pg-guide .chip::after {
  content: ''; position: absolute; inset: 0; z-index: -2;
  clip-path: var(--sc-cut-sm); background: var(--sc-ring);
  transition: background var(--sc-dur);
}
.pg-guide .chip::before {
  content: ''; position: absolute; inset: var(--sc-edge-w); z-index: -1;
  clip-path: var(--sc-cut-sm-in); background: var(--sc-face);
  box-shadow: var(--sc-lift);
}
.pg-guide .chip:hover { --sc-ring: var(--sc-cy-2); color: var(--sc-tx-hi); }
.pg-guide .chip.done { color: var(--sc-cy-ink); }
/* the step you are on is pressed IN, so it stops casting and gains a lip */
.pg-guide .chip.on { --sc-ring: var(--sc-cy); color: var(--sc-cy); filter: none; }
.pg-guide .chip.on:focus-visible::before {
  box-shadow: inset 0 0 0 var(--sc-focus-w) var(--sc-cy);
}
.pg-guide .chip.on::before {
  background: var(--sc-face-well);
  box-shadow:
    inset 0 var(--sc-edge-w) 0 var(--sc-inset-lo),
    inset 0 calc(var(--sc-edge-w) * 3) var(--sc-s2) var(--sc-lip),
    inset 0 0 var(--sc-s3) var(--sc-cy-wash);
}

/* the flow strip */
.pg-guide .flow { margin: var(--sc-s5) 0 var(--sc-s6); }
.pg-guide .flow svg { width: 100%; height: auto; display: block; }
.pg-guide .flow .lane { stroke: var(--sc-edge); stroke-width: 1; fill: none; }
.pg-guide .flow .lane.hot { stroke: var(--sc-cy-2); }
.pg-guide .flow .box { fill: var(--sc-well); stroke: var(--sc-edge); stroke-width: 1; }
.pg-guide .flow .box.hot { fill: var(--sc-plate-hot); stroke: var(--sc-cy); }
.pg-guide .flow text { font: var(--sc-fz-svg) var(--sc-mono); letter-spacing: var(--sc-ls-mid); fill: var(--sc-tx-dim); }
.pg-guide .flow text.hot { fill: var(--sc-cy); }
.pg-guide .flow .pip { fill: var(--sc-cy); opacity: 0; }
.pg-guide .flow .pip.run { animation: sc-flow 1.6s linear infinite; }
@keyframes sc-flow {
  0%   { opacity: 0; transform: translateX(0); }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0; transform: translateX(var(--dx, 60px)); }
}

/* the step plate */
.pg-guide .step { padding: var(--sc-s5) var(--sc-s6) var(--sc-s6); min-height: calc(var(--sc-s8) * 4); }
.pg-guide .step .meta {
  display: flex; align-items: center; gap: var(--sc-s3);
  padding-bottom: var(--sc-s4); margin-bottom: var(--sc-s4);
  border-bottom: var(--sc-edge-w) solid var(--sc-edge-soft);
}
.pg-guide .who {
  padding: var(--sc-s1) var(--sc-s2); border-radius: var(--sc-radius);
  border: var(--sc-edge-w) solid var(--sc-edge);
  font: var(--sc-fz-nano) / 1.4 var(--sc-mono); letter-spacing: var(--sc-ls-mid);
}
.pg-guide .who.super { color: var(--sc-am);  border-color: var(--sc-am-edge); }
.pg-guide .who.admin { color: var(--sc-cy);  border-color: var(--sc-edge-lit); }
.pg-guide .who.member { color: var(--sc-gn); border-color: var(--sc-gn-edge); }
.pg-guide .who.auto { color: var(--sc-tx-dim); }
.pg-guide .step .count {
  margin-left: auto; color: var(--sc-tx-off);
  font: var(--sc-fz-nano) / 1.4 var(--sc-mono); letter-spacing: var(--sc-ls-wide);
}
.pg-guide .step h2 {
  margin-bottom: var(--sc-s4);
  font: 300 var(--sc-fz-title) / 1.3 var(--sc-mono); letter-spacing: var(--sc-ls-mid);
  color: var(--sc-tx-hi);
}
.pg-guide .step .body { display: grid; grid-template-columns: minmax(0, 1fr) var(--sc-aside); gap: var(--sc-s6); }
.pg-guide .step .say { margin-bottom: var(--sc-s4); color: var(--sc-tx); font-size: var(--sc-fz-read); line-height: 1.7; }
.pg-guide .step .say strong { color: var(--sc-tx-hi); font-weight: 600; }
.pg-guide .does {
  padding-left: var(--sc-s4); border-left: var(--sc-bar) solid var(--sc-edge-lit);
  color: var(--sc-tx-dim); font-size: var(--sc-fz-small); line-height: 1.65;
}
.pg-guide .does b { color: var(--sc-tx); font-weight: 600; }
.pg-guide .art { padding: var(--sc-s4); display: grid; place-items: center; min-height: calc(var(--sc-s8) * 2); }
.pg-guide .art svg { width: 100%; height: auto; }
.pg-guide .cap {
  margin-top: var(--sc-s2); text-align: center; color: var(--sc-tx-off);
  font: var(--sc-fz-nano) / 1.4 var(--sc-mono); letter-spacing: var(--sc-ls-wide);
}
.pg-guide code.inline {
  padding: var(--sc-edge-w) var(--sc-s1); background: var(--sc-well);
  border: var(--sc-edge-w) solid var(--sc-edge);
  color: var(--sc-cy); font: var(--sc-fz-small) var(--sc-mono);
}
.pg-guide .live { display: flex; align-items: flex-start; gap: var(--sc-s2); color: var(--sc-tx-dim); font-size: var(--sc-fz-small); }
.pg-guide .live a { color: var(--sc-cy); text-decoration: underline; text-underline-offset: 3px; }
.pg-guide .live a:hover { color: var(--sc-tx-hi); }
.pg-guide .live b { color: var(--sc-tx); font-weight: 600; }
.pg-guide .dot {
  width: var(--sc-s2); height: var(--sc-s2); flex: none; margin-top: 6px; border-radius: var(--sc-radius-dot);
  background: var(--sc-tx-off);
}
.pg-guide .dot.on { background: var(--sc-gn); box-shadow: 0 0 8px var(--sc-gn); }
.pg-guide .dot.off { background: var(--sc-am); }

.pg-guide .stepnav { display: flex; align-items: center; gap: var(--sc-s3); margin-top: var(--sc-s5); }
.pg-guide .stepnav .spacer { flex: 1; }
.pg-guide .stepnav .hint { color: var(--sc-tx-off); font: var(--sc-fz-nano) / 1.4 var(--sc-mono); letter-spacing: var(--sc-ls-mid); }

.pg-guide details.ref { margin-top: var(--sc-s6); }
.pg-guide details.ref summary {
  padding: var(--sc-s3) 0; cursor: pointer; list-style: none;
  color: var(--sc-cy-ink); font: var(--sc-fz-nano) / 1.4 var(--sc-mono);
  letter-spacing: var(--sc-ls-wide);
}
.pg-guide details.ref summary:hover { color: var(--sc-cy); }
.pg-guide details.ref summary::-webkit-details-marker { display: none; }
.pg-guide details.ref summary::before { content: '▸ '; }
.pg-guide details.ref[open] summary::before { content: '▾ '; }
.pg-guide .facts { width: 100%; border-collapse: collapse; margin-top: var(--sc-s3); }
.pg-guide .facts td {
  padding: var(--sc-s3) 0; border-bottom: var(--sc-edge-w) solid var(--sc-edge-soft);
  color: var(--sc-tx-dim); font-size: var(--sc-fz-small); vertical-align: top;
}
.pg-guide .facts td:first-child { width: 42%; padding-right: var(--sc-s5); color: var(--sc-tx); }
.pg-guide .facts tr:last-child td { border-bottom: 0; }

.pg-guide .valve-body { transition: transform .7s cubic-bezier(.4, 1.4, .5, 1); transform-origin: 60px 26px; /* SVG user units, not page pixels */ }
.pg-guide .valve-body.big { transform: scaleY(1.3) scaleX(1.05); }

/* ================================================================== focus ==== */
/* clip-path would eat an outline, so a clipped control shows focus by lighting
   its own edge and ringing its face from the inside */
:focus-visible { outline: var(--sc-bar) solid var(--sc-cy); outline-offset: var(--sc-bar); }
.plate:focus-visible, .btn:focus-visible, .chip:focus-visible, .fcard:focus-visible, .pcard:focus-visible {
  outline: 0; --sc-ring: var(--sc-cy);
}
/* focus lights the ring WITHOUT flattening the plate: the assembly stays in
   the list, the focus ring is added to it */
.plate:focus-visible::before, .btn:focus-visible::before, .chip:focus-visible::before,
.fcard:focus-visible::before, .pcard:focus-visible::before {
  /* one crisp ring and nothing else: the soft inner wash that used to sit with
     it averaged the indicator down to 1.4:1 against what it replaces */
  /* ONE crisp ring and nothing else. A soft inner wash beside it averaged the
     indicator down to 1.4:1, and a dark ring under it to 2.2:1 — the harness
     means the contrast over every pixel the focus state changes, so anything
     low-contrast added to an indicator dilutes it. */
  box-shadow: var(--sc-lift), inset 0 0 0 var(--sc-focus-w) var(--sc-cy);
}
/* THE PRIMARY KEY, WHOSE FOCUS RING WAS FIGHTING ITS OWN WARMTH.
   `.btn:focus-visible` above does two things: it draws the crisp cyan ring on
   ::before, and it swaps --sc-ring from the key's rim colour to cyan. On every
   other key the rim it replaces is dark, so both changes are high contrast. On
   the primary the rim is AMBER, and amber→cyan is 1.2:1 — and the same rule
   also drops the amber inner wash, another wide, low-contrast change. Measured
   at 2.89:1 across the indicator on /lifecycle/'s call to action and on
   /login/'s SIGN IN, with only 1,279 of 3,212 changed pixels reaching 3:1
   against a 1,578-pixel perimeter.
   So the primary keeps its rim and keeps its wash, and focus ADDS the ring
   instead of recolouring the key around it. Fewer pixels change, all of them
   are the indicator, and the button still reads as the warm one. */
.btn--primary:focus-visible { --sc-ring: var(--sc-am); }
.btn--primary:focus-visible::before {
  box-shadow: var(--sc-lift), inset 0 0 var(--sc-s5) var(--sc-am-wash),
              inset 0 0 0 var(--sc-focus-w) var(--sc-cy);
}
.stagenav button:focus-visible { outline: var(--sc-bar) solid var(--sc-cy); outline-offset: calc(-1 * var(--sc-bar)); }

/* ============================================================== responsive === */
/* Breakpoints are the one place a token cannot reach: @media does not accept
   var(). They are the only raw lengths below the token block, and each one
   only re-declares tokens. */
@media (max-width: 1180px) {
  body.pg-lifecycle, body.pg-projects, body.pg-login, body.pg-guide {
    --sc-fz-mega: 28px; --sc-gutter: var(--sc-s5);
  }
  .console { grid-template-columns: var(--sc-navcol-sm) minmax(0, 1fr); }
  .bay-col { padding: var(--sc-s5); }
}
@media (max-width: 900px) {
  body.pg-lifecycle, body.pg-projects, body.pg-login, body.pg-guide {
    --sc-fz-mega: 24px; --sc-s8: 48px;
  }
  .mast { grid-template-columns: 1fr; gap: var(--sc-s5); align-items: start; }
  .readouts { justify-content: flex-start; }
  .ro { text-align: left; min-width: 0; padding-left: 0; padding-right: var(--sc-s6); }
  .console { grid-template-columns: 1fr; }
  .nav-col::after { display: none; }
  .nav-col {
    border-bottom: var(--sc-edge-w) solid var(--sc-edge);
    display: grid; grid-template-columns: var(--sc-navcol-sm) minmax(0, 1fr); gap: var(--sc-s5); align-items: center;
  }
  .stagenav { margin-top: 0; }
  .nav-col .legend { grid-column: 1 / -1; }
  .pg-guide .step .body { grid-template-columns: 1fr; }
  .index { grid-template-columns: 1fr; gap: var(--sc-s2); }
}
@media (max-width: 620px) {
  body.pg-lifecycle, body.pg-projects, body.pg-login, body.pg-guide {
    --sc-gutter: var(--sc-s4); --sc-fz-mega: 21px; --sc-s7: var(--sc-s6);
  }
  .shell { padding-top: var(--sc-s6); }
  .nav-col { grid-template-columns: 1fr; }
  .nav-col #nonagon { max-width: var(--sc-navcol-sm); margin: 0 auto; }
  /* the flow band's labels cannot survive this width, and the phase rail
     above already says the same thing — so it goes rather than shrinks */
  .pg-guide .flow { display: none; }
  .cards, .pg-projects .plist { grid-template-columns: 1fr; }
  .pg-guide .step { padding: var(--sc-s4); }
  .bay-col { padding: var(--sc-s4); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
