/* ==========================================================================
   American Software Solutions — Theme
   --------------------------------------------------------------------------
   Visual language: a candy-swirl lollipop set on brushed stainless steel,
   its wordmark on a strip of hand-cut blue painter's tape. Sweet product,
   serious kitchen — the warmth belongs to the brand, the steel to the room.

   Two accents, and they don't trade jobs:
     --tape   blue, the interface  — links, buttons, focus, active states
     --candy  red, the brand       — the logo, and very little else

   Requires the IBM Plex superfamily. Load it in the document <head>:

     <link rel="preconnect" href="https://fonts.googleapis.com">
     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
     <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@500&family=IBM+Plex+Sans+Condensed:wght@600;700&family=IBM+Plex+Sans:wght@400;500&display=swap" rel="stylesheet">

   Contents
     1. Tokens
     2. Dark mode
     3. Reset & base
     4. Typography
     5. Layout
     6. Components
     7. Motion
     8. Utilities
   ========================================================================== */


/* 1. Tokens ============================================================== */

:root {
  /* -- Surface: brushed stainless -------------------------------------- */
  --steel-hi:    #EDEFF0;   /* raking highlight, top of the sheet          */
  --steel-mid:   #D8DDDF;   /* body of the sheet                          */
  --steel-lo:    #E4E8E9;   /* return light, bottom                       */

  /* Grain flecks that make the steel read as brushed, not flat */
  --grain-hi:    rgba(255, 255, 255, 0.5);
  --grain-lo:    rgba(20, 24, 26, 0.035);

  /* -- Ink -------------------------------------------------------------- */
  --ink:         #14181A;   /* Sharpie black                              */
  --ink-soft:    #4A5257;   /* secondary copy, captions                   */

  /* -- Accent: blue painter's tape --------------------------------------
     The *interface* accent. Links, focus rings, buttons, active states.
     ---------------------------------------------------------------------- */
  --tape:        #2C7FBE;
  --tape-edge:   #1F6099;   /* the shadowed lower edge of a taped strip   */
  --tape-ink:    #F4F8FB;   /* text written on tape                       */

  /* -- Brand: the lollipop ----------------------------------------------
     The *brand* accent, and the only warm colour in the system. It belongs
     to the logo. Don't spend it on buttons or links — blue does that job,
     and the candy stops being special the moment it's everywhere.
     ---------------------------------------------------------------------- */
  --candy:       #E8384F;   /* the swirl                                  */
  --candy-deep:  #B4283C;   /* the rim that defines the pop's edge        */
  --candy-cream: #FFF6EC;   /* the sugar between the stripes              */
  --candy-stick: #E7DCCB;   /* paper stick                                */

  /* -- Flag --------------------------------------------------------------
     The one interface job the warm accent is allowed to take: something
     went wrong and the reader has to see it. Aliased rather than used
     directly so error states never reach for --candy by name.
     ---------------------------------------------------------------------- */
  --flag:        var(--candy-deep);

  /* -- Panels & lines ---------------------------------------------------- */
  --panel:       rgba(255, 255, 255, 0.44);
  --panel-edge:  rgba(255, 255, 255, 0.6);
  --rule:        rgba(20, 24, 26, 0.14);

  --shadow-1:    0 3px 10px rgba(20, 24, 26, 0.22);
  --shadow-2:    0 12px 34px rgba(20, 24, 26, 0.14);

  /* -- Screen ------------------------------------------------------------
     The display over the pass. A dark hardware bezel, and the violet the
     artwork throws onto the counter under it. --screen-glow is sampled from
     the artwork itself, which is the only reason a third hue is allowed in
     the system: it is light, not paint. Nothing else may use it.
     ---------------------------------------------------------------------- */
  --screen-case-hi: #23282B;   /* top of the moulded bezel                 */
  --screen-case-lo: #0E1113;   /* its shadowed lower half                  */
  --screen-glow:    rgba(124, 90, 168, 0.42);
  --screen-bezel:   clamp(0.5rem, 1.4vw, 0.9rem);
  --screen-h:       min(50svh, 30rem);   /* caps the frame so the copy under
                                            it still clears a laptop fold  */

  /* -- Fruit --------------------------------------------------------------
     The one full palette in the system, and the reason it is allowed: these
     are pictures of fruit. A blue strawberry is not a stylistic choice, it
     is a mistake. Fenced the way --screen-* is fenced — only a fruit mark
     may touch these. Interface colour is still --tape; brand is still
     --candy.

     Deliberately *not* redefined for dark mode, on the same logic that keeps
     the screen bezel dark in both: a lemon is yellow in a dark room too.
     ---------------------------------------------------------------------- */
  --fruit-berry:  #E8384F;   /* strawberry                                 */
  --fruit-lemon:  #EFC04A;
  --fruit-orange: #EC8A3C;
  --fruit-pear:   #86B24A;
  --fruit-melon:  #EE6377;   /* watermelon flesh                           */
  --fruit-rind:   #4E9153;   /* and its rind                               */
  --fruit-kiwi:   #B7D46A;
  --fruit-skin:   #8B6B45;   /* kiwi skin                                  */
  --fruit-leaf:   #5FA05A;
  --fruit-stem:   #7A6A52;
  --fruit-seed:   #3C4A2E;
  --fruit-pith:   #FFF6EC;   /* seeds, pith, the shine on a peel           */

  /* -- Swag ---------------------------------------------------------------
     Merchandise, drawn rather than photographed. Fenced on the same terms as
     --fruit-*: cotton is not an interface colour and never becomes one, and
     nothing outside a .swag drawing may reach for these.

     Also not redefined for dark mode, for the fruit reason — a heather tee is
     heather in a dark room. What changes with the room is the stage the
     garment sits on, and that is built from --panel and --rule, which do flip.
     ---------------------------------------------------------------------- */
  --swag-cotton:       #D6DADC;   /* heather grey, the tee                  */
  --swag-cotton-fold:  #BFC5C8;   /* its sleeves and the shaded folds       */
  --swag-charcoal:     #3A4247;   /* the cap, and the hoodie                */
  --swag-charcoal-fold:#2C3337;
  --swag-canvas:       #47535A;   /* backpack canvas                        */
  --swag-canvas-fold:  #38434A;
  --swag-strap:        #222A2E;   /* webbing, zips, drawstrings             */
  --swag-metal:        #9AA4AA;   /* bottle steel, grommets, hardware       */
  --swag-paper:        #F7F4EE;   /* sticker vinyl                          */

  /* -- The steel field itself, as one reusable value --------------------- */
  --steel-field:
    repeating-linear-gradient(90deg, var(--grain-hi) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, var(--grain-lo) 0 1px, transparent 1px 2px),
    linear-gradient(160deg, var(--steel-hi) 0%, var(--steel-mid) 55%, var(--steel-lo) 100%);

  /* -- Type ------------------------------------------------------------- */
  --font-display: "IBM Plex Sans Condensed", "IBM Plex Sans", sans-serif;
  --font-body:    "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  --font-mono:    "IBM Plex Mono", ui-monospace, SFMono-Regular, monospace;

  --size-display-xl: clamp(2.75rem, 1.5rem + 6.2vw, 6.5rem);
  --size-display-l:  clamp(2rem, 1.35rem + 3.2vw, 3.75rem);
  --size-display-m:  clamp(1.5rem, 1.2rem + 1.5vw, 2.25rem);
  --size-body:       clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --size-mono:       clamp(0.9rem, 0.85rem + 0.2vw, 1rem);
  --size-label:      clamp(0.75rem, 0.7rem + 0.2vw, 0.875rem);
  --size-meta:       0.6875rem;

  --track-display: -0.022em;  /* tight, so condensed caps lock together   */
  --track-label:    0.22em;   /* wide, like stencilled equipment labels   */
  --track-meta:     0.16em;

  /* -- Space ------------------------------------------------------------ */
  --space-1: 0.5rem;
  --space-2: 0.75rem;
  --space-3: 1.1rem;
  --space-4: clamp(1.5rem, 3.5vw, 2.25rem);
  --space-5: clamp(1.75rem, 4vw, 2.75rem);
  --space-6: clamp(3rem, 8vh, 5rem);
  --gutter:  clamp(1.5rem, 5vw, 4rem);

  --measure:  46rem;   /* page shell                                      */
  --measure-wide: 60rem; /* shell for a view led by a full-width image    */
  --measure-copy: 34ch; /* comfortable reading width for body copy        */
  --measure-lede: 64ch; /* the standfirst under a headline — see .lede    */
  --measure-prose: 62ch; /* longer line, for documents read top to bottom */

  /* -- Motion ----------------------------------------------------------- */
  --ease-settle: cubic-bezier(0.2, 0.8, 0.25, 1);
  --ease-nudge:  cubic-bezier(0.2, 0.7, 0.3, 1);
  --dur-fast:    160ms;
  --dur-mid:     620ms;
  --dur-slow:    700ms;
}


/* 2. Dark mode ===========================================================
   Same sheet of steel, lit from a colder angle — gunmetal, not black.

   Applied two ways, and the two blocks below must be kept in sync:
     - by system preference, unless the page forces light
     - by <html data-theme="dark">, which wins over the system preference
   Set data-theme="light" to force light mode on a dark-mode system.
   ======================================================================== */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --steel-hi:   #1E2325;
    --steel-mid:  #14181A;
    --steel-lo:   #191E20;

    --grain-hi:   rgba(255, 255, 255, 0.045);
    --grain-lo:   rgba(0, 0, 0, 0.16);

    --ink:        #E8EDEF;
    --ink-soft:   #98A3A8;

    --tape:       #2A76B0;
    --tape-edge:  #17557F;
    --tape-ink:   #EEF5FA;

    /* Candy stays candy — brightened just enough to hold up on gunmetal. */
    --candy:       #F0566B;
    --candy-deep:  #C2304A;
    --candy-cream: #FFF6EC;
    --candy-stick: #D9CDB8;

    /* The deep rim goes muddy on gunmetal; the swirl itself carries. */
    --flag:        var(--candy);

    --panel:      rgba(255, 255, 255, 0.045);
    --panel-edge: rgba(255, 255, 255, 0.09);
    --rule:       rgba(232, 237, 239, 0.16);

    --shadow-1:   0 3px 10px rgba(0, 0, 0, 0.5);
    --shadow-2:   0 12px 34px rgba(0, 0, 0, 0.45);

    /* A lit screen carries further in a dark room. */
    --screen-case-hi: #2A3033;
    --screen-case-lo: #0B0E0F;
    --screen-glow:    rgba(139, 102, 189, 0.6);
  }
}

:root[data-theme="dark"] {
  --steel-hi:   #1E2325;
  --steel-mid:  #14181A;
  --steel-lo:   #191E20;

  --grain-hi:   rgba(255, 255, 255, 0.045);
  --grain-lo:   rgba(0, 0, 0, 0.16);

  --ink:        #E8EDEF;
  --ink-soft:   #98A3A8;

  --tape:       #2A76B0;
  --tape-edge:  #17557F;
  --tape-ink:   #EEF5FA;

  /* Candy stays candy — brightened just enough to hold up on gunmetal. */
  --candy:       #F0566B;
  --candy-deep:  #C2304A;
  --candy-cream: #FFF6EC;
  --candy-stick: #D9CDB8;

  /* The deep rim goes muddy on gunmetal; the swirl itself carries. */
  --flag:        var(--candy);

  --panel:      rgba(255, 255, 255, 0.045);
  --panel-edge: rgba(255, 255, 255, 0.09);
  --rule:       rgba(232, 237, 239, 0.16);

  --shadow-1:   0 3px 10px rgba(0, 0, 0, 0.5);
  --shadow-2:   0 12px 34px rgba(0, 0, 0, 0.45);

  /* A lit screen carries further in a dark room. */
  --screen-case-hi: #2A3033;
  --screen-case-lo: #0B0E0F;
  --screen-glow:    rgba(139, 102, 189, 0.6);
}

/* Tell form controls and scrollbars which mode they're in. */
:root { color-scheme: light dark; }
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }


/* 3. Reset & base ======================================================== */

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  min-height: 100svh;
  padding: var(--gutter);

  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--size-body);
  line-height: 1.6;

  background-color: var(--steel-mid);
  background-image: var(--steel-field);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; }

:focus-visible {
  outline: 2px solid var(--tape);
  outline-offset: 4px;
  border-radius: 1px;
}


/* 4. Typography ========================================================== */

h1, h2, h3, .display-xl, .display-l, .display-m {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: var(--track-display);
  text-wrap: balance;
}

h1, .display-xl { font-size: var(--size-display-xl); }
h2, .display-l  { font-size: var(--size-display-l); }
h3, .display-m  { font-size: var(--size-display-m); line-height: 1.1; }

/* Lede — the one sentence under a headline. */
/* The standfirst under a page headline. It ran at --measure-copy (34ch) back
   when every lede was one short sentence; they have all grown past that, and at
   34ch a two-clause sentence breaks into a narrow column that leaves most of
   the counter empty next to a headline spanning the full shell. 64ch is still
   inside the comfortable 45–75ch band, and sits under the headline rather than
   beside it. Body copy elsewhere keeps the tighter --measure-copy. */
.lede {
  margin: var(--space-4) 0 0;
  max-width: var(--measure-lede);
  color: var(--ink-soft);
}

/* Eyebrow — a stencilled label above a heading. Not on tape. */
.eyebrow {
  margin: 0 0 var(--space-2);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Meta — the smallest utility text: footers, timestamps, statuses. */
.meta {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-soft);
}


/* 5. Layout ============================================================== */

/* .page — full-height frame: content centered, footer pinned to the bottom. */
.page {
  display: grid;
  grid-template-rows: 1fr auto;
  min-height: calc(100svh - (var(--gutter) * 2));
}

/* .shell — the measure everything aligns to. */
.shell {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
}

/* .shell--wide — for a view that needs to lay things out side by side: a
   card grid, a table. Copy inside it still takes its own measure. */
.shell--wide { max-width: var(--measure-wide); }

/* .shell--screen — a shell for a view led by a .screen. It takes the frame's
   own width, so the picture and the copy under it share one left edge instead
   of the frame floating centred inside a wider column. */
.shell--screen { max-width: min(var(--measure-wide), calc(var(--screen-h) * 16 / 9)); }

/* .stack — vertical rhythm for a run of blocks. */
.stack { display: flex; flex-direction: column; }
.stack > * + * { margin-top: var(--space-4); }

.center-y {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* Centred content that outgrows the viewport overflows in *both* directions,
   and the top half becomes unreachable — no scrollbar goes that way. Safe
   centring falls back to flex-start the moment that would happen. Declared
   separately: a browser that doesn't know the keyword drops the whole rule. */
@supports (justify-content: safe center) {
  .center-y { justify-content: safe center; }
}


/* 6. Components ========================================================== */

/* -- Logo ---------------------------------------------------------------
   The lollipop mark, leaning the way a pop leans when you set it down.
   .lockup pairs it with the wordmark on tape: candy taped to the counter.
   ---------------------------------------------------------------------- */
.lockup {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* .tape pins itself to flex-start for column layouts; centre it in a lockup. */
.lockup > .tape { align-self: center; }

.logo-mark {
  flex: none;
  width: auto;
  height: clamp(2.75rem, 6.5vw, 4rem);
}

.logo-mark--sm { height: 2.25rem; }

/* The lollipop leans the way a pop leans when you set it down. Upright marks
   (the ASS mark) don't take this. */
.logo-mark--lean {
  transform: rotate(7deg);
  transform-origin: bottom center;
}

a.lockup { text-decoration: none; }

/* -- Tape ---------------------------------------------------------------
   The signature. A strip of blue painter's tape torn off the roll and
   pressed onto the steel: uneven ends, translucent weave, lifted edge.
   Use it once per view — it stops being an artifact if it repeats.
   ---------------------------------------------------------------------- */
.tape {
  display: inline-block;
  align-self: flex-start;
  margin: 0;
  padding: 0.7rem 1.6rem 0.75rem;

  background-color: var(--tape);
  background-image: repeating-linear-gradient(
    92deg,
    rgba(255, 255, 255, 0.07) 0 2px,
    rgba(0, 0, 0, 0.05) 2px 4px
  );
  border-top: 1px solid rgba(255, 255, 255, 0.22);
  border-bottom: 1px solid var(--tape-edge);
  box-shadow: var(--shadow-1);

  /* uneven ends, the way tape tears off the roll */
  clip-path: polygon(0.7% 0, 100% 2.5%, 99.2% 100%, 0 96%);
  transform: rotate(-1.4deg);
  transform-origin: left center;

  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--tape-ink);
  text-decoration: none;
}

/* Torn the other way — alternate so repeat uses don't look stamped. */
.tape--right { transform: rotate(1.1deg); transform-origin: right center; }
.tape--flat  { transform: none; }

a.tape:hover,
a.tape:focus-visible { color: #fff; }

/* -- Mono link ----------------------------------------------------------
   Underlined in tape blue, with an arrow that steps forward on hover.
   ---------------------------------------------------------------------- */
.link-mono {
  display: inline-flex;
  align-items: baseline;
  gap: 0.6rem;
  padding-bottom: 0.2rem;

  color: var(--ink);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-mono);
  text-decoration: none;
  border-bottom: 2px solid var(--tape);
  transition: color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

.link-mono .arrow { transition: transform 220ms var(--ease-nudge); }

.link-mono:hover,
.link-mono:focus-visible { color: var(--tape); }

.link-mono:hover .arrow,
.link-mono:focus-visible .arrow { transform: translateX(0.35rem); }

/* -- Button -------------------------------------------------------------
   Equipment-panel switch: square, labelled, no gloss.
   ---------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.85rem 1.5rem;
  border: 1px solid transparent;
  border-radius: 2px;
  cursor: pointer;

  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  text-decoration: none;
  transition: background-color var(--dur-fast) ease,
              border-color var(--dur-fast) ease,
              color var(--dur-fast) ease;
}

.btn--primary {
  background-color: var(--tape);
  border-color: var(--tape-edge);
  color: var(--tape-ink);
}
.btn--primary:hover,
.btn--primary:focus-visible { background-color: var(--tape-edge); }

.btn--ghost {
  background-color: transparent;
  border-color: var(--rule);
  color: var(--ink);
}
.btn--ghost:hover,
.btn--ghost:focus-visible { border-color: var(--tape); color: var(--tape); }

/* -- Panel --------------------------------------------------------------
   A lighter plate set on the steel field. For grouped content on
   interior pages.
   ---------------------------------------------------------------------- */
.panel {
  padding: clamp(1.25rem, 3vw, 2rem);
  background-color: var(--panel);
  border: 1px solid var(--panel-edge);
  border-radius: 3px;
  box-shadow: var(--shadow-2);
  backdrop-filter: blur(6px);
}

/* -- Card grid ----------------------------------------------------------
   A row of small plates on the counter — capabilities, services, the four
   marks. Wraps to two-up and then one-up on its own; no breakpoints needed.
   Pair with .panel for the plate itself.

     <div class="card-grid">
       <div class="panel"><p class="eyebrow">Label</p><p>One line.</p></div>
     </div>
   ---------------------------------------------------------------------- */
.card-grid {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

/* Column counts for a set of a known size. Left to itself, auto-fit packs in
   as many 13rem columns as will fit and strands the remainder on a short last
   row — four cards become 3 + 1, six become 4 + 2. Raising the floor caps the
   count without a breakpoint: the min() keeps the floor honest, collapsing to
   a single column once the column is narrower than the floor itself.

     --2   a set of four, two-up      (18rem floor: 3 columns can't fit)
     --3   a set of six, three-up     (17rem floor: 4 columns can't fit)  */
.card-grid--2 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}

.card-grid--3 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}

.card-grid > .panel > :last-child { margin-bottom: 0; }

/* -- Fruit ---------------------------------------------------------------
   The one place the system carries a full palette, and the reason it is
   allowed: these are pictures of fruit, and a blue strawberry is not a
   stylistic choice, it is a mistake. Treated the way --screen-glow is
   treated — a carve-out with a fence around it. Nothing but a fruit mark
   may use these; interface colour is still --tape, brand is still --candy.
   ---------------------------------------------------------------------- */
.card-icon {
  display: block;
  width: auto;
  height: 2.5rem;
  margin-bottom: var(--space-2);
}

/* -- Swag ---------------------------------------------------------------
   A piece of merchandise on a plate. The garment is drawn in SVG from the
   --swag-* palette; the mark itself is the real mark.svg laid over it, so
   what a visitor sees printed on the tee is the actual logo file and not a
   redrawing of it that can drift out of step.

   Each product puts the mark somewhere different, so placement is four
   custom properties set by the modifier rather than six near-identical
   rules. Percentages are of the stage, so the whole thing scales with the
   column and needs no breakpoints.

     <figure class="swag swag--tee">
       <div class="swag__stage">
         <svg class="swag__art" viewBox="0 0 200 150">…</svg>
         <img class="swag__mark" src="/assets/mark.svg" alt="">
       </div>
       <figcaption class="swag__caption">
         <span class="swag__name">ASS Tee</span>
         <span class="swag__detail">Heather grey, mark on the chest</span>
       </figcaption>
     </figure>
   ---------------------------------------------------------------------- */
.swag {
  margin: 0;
}

.swag__stage {
  position: relative;
  aspect-ratio: 4 / 3;
  margin-bottom: var(--space-3);
  border-radius: 2px;
  background-color: var(--panel);
  border: 1px solid var(--panel-edge);
  overflow: hidden;

  /* A studio sweep behind the product. Barely there in light mode; in dark
     mode it is what keeps a charcoal cap from disappearing into a charcoal
     panel, since the garment palette deliberately does not flip with the
     theme and the plate behind it does. */
  background-image: radial-gradient(115% 85% at 50% 42%,
                    rgba(255, 255, 255, 0.11) 0%, transparent 72%);

  /* Fences the mark's multiply blend to the stage. Without it the blend
     reaches past the panel and multiplies against the steel field behind. */
  isolation: isolate;
}

.swag__art {
  display: block;
  width: 100%;
  height: 100%;
}

.swag__mark {
  position: absolute;
  left: var(--mark-x, 50%);
  top: var(--mark-y, 50%);
  width: var(--mark-w, 22%);
  height: auto;
  transform: translate(-50%, -50%) rotate(var(--mark-r, 0deg));

  /* The mark is printed on cloth, not floating above it. A touch of the
     garment's own shading through the artwork is what sells that. */
  mix-blend-mode: multiply;
}

/* multiply over a dark garment turns the mark to mud, so the dark products
   get it back as normal compositing and lean on the drop shadow instead. */
.swag--cap .swag__mark,
.swag--hoodie .swag__mark,
.swag--pack .swag__mark {
  mix-blend-mode: normal;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
}

/* Percentages of the stage, which shares the artwork's 4:3 box — so these read
   straight off the SVG's own 200x150 coordinates. */
.swag--tee    { --mark-x: 50%; --mark-y: 53%; --mark-w: 19%; }
.swag--cap    { --mark-x: 50%; --mark-y: 48%; --mark-w: 19%; }
.swag--pack   { --mark-x: 50%; --mark-y: 33%; --mark-w: 20%; }
.swag--hoodie { --mark-x: 50%; --mark-y: 51%; --mark-w: 18%; }
.swag--bottle { --mark-x: 50%; --mark-y: 56%; --mark-w: 15%; }
.swag--decal  { --mark-x: 50%; --mark-y: 50%; --mark-w: 30%; --mark-r: -4deg; }

.swag__caption {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.swag__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.0625rem;
  letter-spacing: var(--track-display);
  color: var(--ink);
}

.swag__detail {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* -- Notice -------------------------------------------------------------
   A short status message: something was sent, or something needs fixing.
   A plate on the steel with a painted stripe down its leading edge.

     <p class="notice">Message sent.</p>
     <p class="notice notice--flag">Something needs fixing.</p>
   ---------------------------------------------------------------------- */
.notice {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  max-width: var(--measure-prose);

  background-color: var(--panel);
  border: 1px solid var(--panel-edge);
  border-left: 3px solid var(--tape);
  border-radius: 2px;
}

.notice--flag { border-left-color: var(--flag); }

.notice > :first-child { margin-top: 0; }
.notice > :last-child  { margin-bottom: 0; }

/* -- Form ---------------------------------------------------------------
   Fields are let into the counter rather than set on top of it: a shallow
   well, a dark inner lip, and the tape blue only when the field is live.
   Labels are stencilled like everything else that names a piece of
   equipment.

     <form class="form">
       <p class="field">
         <label class="label" for="name">Name</label>
         <input class="input" id="name" name="name" type="text">
       </p>
     </form>
   ---------------------------------------------------------------------- */
.form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 34rem;
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: 0;
}

.label {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* The asterisk is decoration — the word "required" is what gets announced. */
.label .req { color: var(--tape); }

.input,
.textarea {
  width: 100%;
  padding: 0.7rem 0.85rem;

  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--size-body);
  line-height: 1.5;

  background-color: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 2px;
  box-shadow: inset 0 1px 2px rgba(20, 24, 26, 0.09);
  transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

.textarea {
  min-height: 9rem;
  resize: vertical;
}

.input::placeholder,
.textarea::placeholder { color: var(--ink-soft); opacity: 0.75; }

/* The default focus ring is an outline offset *outside* the box, which reads
   as a halo around a field rather than the field switching on. Swap it for a
   ring drawn tight to the border — same colour, same job, no gap. */
.input:focus,
.textarea:focus {
  outline: none;
  border-color: var(--tape);
  box-shadow: inset 0 1px 2px rgba(20, 24, 26, 0.09),
              0 0 0 3px rgba(44, 127, 190, 0.24);
}

/* Set by the server on a field that came back wrong, alongside the message
   in .field-note — never colour alone. */
.input[aria-invalid="true"],
.textarea[aria-invalid="true"] { border-color: var(--flag); }

.field-note {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ink-soft);
}

.field-note--flag { color: var(--flag); }

/* -- Prose --------------------------------------------------------------
   Long-form document copy: policies, terms, notices — pages that are read
   top to bottom rather than scanned. It carries its own measure and its own
   vertical rhythm: .lede is a standfirst that stops after a sentence or two,
   while a document keeps going, and the two want different rhythm even though
   their line lengths now sit close together.

   Section headings step down to --size-display-m. Inside a document a
   heading is a signpost, not a headline, and an h2 at display-l would
   shout over the title of the page it sits under.

     <div class="prose">
       <h2>Section</h2>
       <p>…</p>
     </div>

   Bullets are a short stroke of tape rather than a disc — the same mark
   that gets drawn on a container lid, at the size a list can carry it.
   ---------------------------------------------------------------------- */
.prose { max-width: var(--measure-prose); }

.prose > * { margin-top: var(--space-3); margin-bottom: 0; }
.prose > :first-child { margin-top: 0; }

.prose h2 {
  margin-top: var(--space-5);
  font-size: var(--size-display-m);
  line-height: 1.1;
}

.prose h3 {
  margin-top: var(--space-4);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Plex Sans is loaded at 400 and 500 only — 700 here would be synthesised. */
.prose strong { font-weight: 500; }

/* Inline links. .prose applies this to every anchor inside it; use .link
   directly for a link in a lede, a caption, or anywhere else in running copy
   — a bare <a> has no house style and falls back to browser blue. */
.link,
.prose a {
  color: var(--tape);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  transition: color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

.link:hover,
.link:focus-visible,
.prose a:hover,
.prose a:focus-visible { color: var(--ink); border-bottom-color: var(--tape); }

.prose ul { padding-left: 0; list-style: none; }
.prose li { position: relative; padding-left: 1.5rem; }
.prose li + li { margin-top: var(--space-1); }

.prose li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.68em;
  width: 0.6rem;
  height: 2px;
  background-color: var(--tape);
}

.prose hr {
  margin-top: var(--space-5);
  height: 1px;
  border: 0;
  background-color: var(--rule);
}

/* -- Screen -------------------------------------------------------------
   The display over the pass. Artwork that arrives with its own palette does
   not get blended into the steel — it gets a hardware bezel, a shadow, and
   the light it throws onto the counter beneath it. Framed that way it reads
   as something switched on in the room, so its colours are the picture's
   business rather than a second brand fighting the first.

   --screen-h caps the height, and the 16:9 max-width is derived from it, so
   the frame gives ground on short viewports instead of pushing the copy off
   the fold. Set --screen-h locally for other ratios.

   Like .tape, one per view.

     <figure class="screen">
       <img src="…" alt="…" width="1280" height="720">
       <p class="tape screen__tab">In prep</p>
     </figure>
   ---------------------------------------------------------------------- */
.screen {
  position: relative;
  width: 100%;
  max-width: calc(var(--screen-h) * 16 / 9);
  margin: 0 auto;
  padding: var(--screen-bezel);
  border-radius: 5px;

  background-image: linear-gradient(168deg, var(--screen-case-hi), var(--screen-case-lo));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),   /* moulding, catching the light */
    0 0 0 1px rgba(0, 0, 0, 0.4),              /* the seam of the case         */
    var(--shadow-2),
    0 26px 64px -20px var(--screen-glow);      /* what it spills on the steel  */
}

.screen > img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 2px;

  /* The artwork's own background, so the glass is already dark on a slow
     connection and the frame doesn't flash white before the file paints. */
  background-color: #14192C;
}

/* A strip torn off and stuck across the case, half on it and half on the
   steel — the one thing tying the picture to the room it sits in. Runs
   tighter than a standalone .tape: it labels the object, it isn't the
   headline. The overlap is measured down from the frame's bottom edge, so it
   stays a constant sliver of case at every frame size rather than eating a
   tenth of the picture on a phone. Offset with margin, never a transform —
   .anim-tape needs the transform to itself. */
.screen__tab {
  position: absolute;
  left: clamp(1rem, 6%, 3rem);
  top: 100%;
  margin-top: calc((var(--screen-bezel) + 0.3rem) * -1);
  z-index: 1;
  padding: 0.5rem 1.15rem 0.55rem;
}

/* -- Actions ------------------------------------------------------------
   A row of links or buttons closing out a block of copy.
   ---------------------------------------------------------------------- */
.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  margin: var(--space-5) 0 0;
}

/* -- Rule ---------------------------------------------------------------- */
.rule {
  height: 1px;
  margin: 0;
  border: 0;
  background-color: var(--rule);
}

/* -- Site header --------------------------------------------------------- */
.site-header {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-4);
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-5);
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.site-nav a {
  color: var(--ink-soft);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
  transition: color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

.site-nav a:hover,
.site-nav a:focus-visible,
.site-nav a[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--tape);
}

/* -- Site footer --------------------------------------------------------- */
.site-footer {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  justify-content: space-between;

  margin-top: var(--space-6);
  padding-top: var(--space-3);
  border-top: 1px solid var(--rule);

  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--size-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-soft);
}

.site-footer a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--rule); }
.site-footer a:hover,
.site-footer a:focus-visible { color: var(--ink); border-bottom-color: var(--tape); }


/* 7. Motion ==============================================================
   One orchestrated load-in: the tape settles, then the headline rises.
   Opt in per element with .anim-*; stagger with .delay-*.
   ======================================================================== */

@keyframes tape-settle {
  from { opacity: 0; transform: translateY(-14px) rotate(-5.5deg); }
  to   { opacity: 1; transform: translateY(0) rotate(-1.4deg); }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(100%); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes fade-up {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* The screen comes on: the panel lifts into place as the backlight catches. */
@keyframes screen-wake {
  from { opacity: 0; transform: translateY(10px) scale(0.985); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* The pop is set down on the counter: drops in and rocks to rest. */
@keyframes pop-set-down {
  0%   { opacity: 0; transform: translateY(-18px) rotate(-12deg) scale(0.82); }
  60%  { opacity: 1; transform: translateY(0) rotate(11deg) scale(1); }
  100% { opacity: 1; transform: translateY(0) rotate(7deg) scale(1); }
}

/* .rise clips its child so the line appears to slide out from behind a mask.
   Put .rise on the wrapper and .anim-rise on the child it clips. */
.rise { display: block; overflow: hidden; }
.rise > * { display: block; }

@media (prefers-reduced-motion: no-preference) {
  .anim-pop    { animation: pop-set-down 760ms var(--ease-settle) both; }
  .anim-screen { animation: screen-wake 820ms var(--ease-settle) both; }
  .anim-tape { animation: tape-settle var(--dur-mid) var(--ease-settle) both; }
  .anim-rise { animation: rise var(--dur-slow) var(--ease-settle) both; }
  .anim-up   { animation: fade-up var(--dur-slow) ease-out both; }

  /* An even ladder, so a page can cascade top to bottom without doing maths. */
  .delay-1 { animation-delay: 160ms; }
  .delay-2 { animation-delay: 280ms; }
  .delay-3 { animation-delay: 400ms; }
  .delay-4 { animation-delay: 520ms; }
  .delay-5 { animation-delay: 640ms; }
  .delay-6 { animation-delay: 760ms; }
}


/* 8. Utilities =========================================================== */

.measure-copy { max-width: var(--measure-copy); }
.ink-soft     { color: var(--ink-soft); }
.mt-4 { margin-top: var(--space-4); }
.mt-5 { margin-top: var(--space-5); }
.mb-5 { margin-bottom: var(--space-5); }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
