/* ============================================================
   Studio design system: core components
   Rules shared by every sheet and output. Values come only from
   tokens.css; link this file right after it:
     <link rel="stylesheet" href="tokens.css">
     <link rel="stylesheet" href="components.css">
   Component classes carry the c- prefix so no page class (a sheet
   called "plastic", say) can pick them up by accident.
   check_tokens.py scans this file through every page that links it,
   and fails any element that is both .c-plastic and .sheet.
   ============================================================ */
@import "ink-rules.css";   /* the pre-inked line assets (generated by tools/studio/ink_rules.py) */

/* --- Clear plastic: the frosted panel, F2 Edge-lit ----------------
   Locked 30 Oct (Aaron; tokens.css, Material 2): the sleek
   counterweight to raw ink and concrete. A soft frost with a cool
   neutral cast and a faint fine grain, a white rim inked top and left,
   a faint deep-blue far edge inked right and bottom, squircle corners,
   a soft, tight shadow. No electric, no glow. It lifts a panel; what
   lies under it shows as soft shape. Built and measured in
   plastic-studies.html (build_plastic_studies.py, round 3); the 14 px
   panel it replaces is archived in studio-system/archive/
   2026-10-30-components-pre-redo.css.

   Use: class="c-plastic". It is position: relative by default so its
   layers stay panel-sized in normal flow; a page may set absolute or
   fixed to place it. Add .on-deep when the panel sits over a deep-blue
   field (31 Oct): the frost thins
   (--plastic-frost-on-deep) so paper text holds, and the white rim
   carries the edge (rules.md 4.3). Add .on-ink over an ink field
   (rules.md 3.1b; CMF round 7): the same thin frost on screen, and on
   paper its own premixed fill, --plastic-print-fill-on-ink. Frost always carries its edges and
   the contact shadow (ban 14).
   Deprecated: .on-4 (the smoked panel over concrete-4, which left the
   system on 31 Oct) is kept only so archives and cmf.html render;
   check_tokens.py fails it on any other page.

   Corners: border-radius --plastic-radius with corner-shape: squircle.
   corner-shape renders only in Chromium 139 and later; Safari and
   Firefox ignore it and draw a 22 px round corner (the edges' drawn
   squircle corner is then clipped to the round one).

   Edges: both are drawn in the ink hand by tools/studio/ink_rules.py
   and baked with their colour (--ink-rule-rim-lit, --ink-rule-rim-far
   in ink-rules.css), so they are plain images on screen and on paper.
   The far edge is decorative: 2.83:1 on paper and lost on a deep
   field; the white rim carries the edge.

   Grain: plastic-studies/grain-f2.png, written by
   build_plastic_studies.py (grain_tile, fixed seed), shown at
   --plastic-grain-size.

   Rule: a panel holds text, marks and line art only. Never a whole
   page section and never a sheet: on paper the panel's shadow layer is
   rasterised, so keep it to a panel-sized box.

   Screen: translucent frost + grain + backdrop blur + box-shadow; the
   edges are the ::after layer, drawn over the panel's edge.

   Print (default, no authoring): Chromium's print-to-PDF drops
   backdrop-filter and prints a blurred box-shadow as a flat grey
   rectangle. So on paper the panel's own background goes transparent
   and a ::before layer behind its content carries the pre-mixed opaque
   fill (--plastic-print-fill-on-0 / -on-deep) with the grain, and
   --plastic-shadow-print. Only that layer is rasterised; the panel's
   text stays vector and selectable. Lines under the panel are hidden
   on paper.

   Print, opt-in show-through (hero panels only): add the attribute
   data-plastic-show and give the panel a direct child
     <div class="c-plastic-under" aria-hidden="true"><div>…copy…</div></div>
   The .c-plastic-under box clips to the panel; the page positions the
   inner copy of what the panel covers so it lines up (SVG art can be
   copied with <use href="#id">). On paper the copy shows, blurred like
   the backdrop, under the frost. check_tokens.py fails any
   data-plastic-show without a .c-plastic-under child.
   ---------------------------------------------------------------- */
.c-plastic {
  position: relative;      /* anchors the ::before/::after layers; a page's own position wins */
  box-sizing: border-box;
  isolation: isolate;
  background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-frost);
  -webkit-backdrop-filter: var(--plastic-backdrop);
  backdrop-filter: var(--plastic-backdrop);
  border-radius: var(--plastic-radius);
  corner-shape: squircle;
  box-shadow: var(--plastic-shadow);
}
.c-plastic.on-deep, .c-plastic.on-ink, .c-plastic.on-4 {   /* .on-ink: over an ink field, the same thin frost; .on-4: deprecated alias */
  color: var(--paper);
  background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-frost-on-deep);
}
.c-plastic::before, .c-plastic::after, .c-plastic > .c-plastic-under { corner-shape: inherit; }
.c-plastic::after {                       /* the edges, over the panel's edge, in the ink hand */
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;                 /* clips the edges' far ends to the panel's corners */
  background: var(--ink-rule-rim-lit) left top no-repeat, var(--ink-rule-rim-far) right bottom no-repeat;
  pointer-events: none;
}
.c-plastic[data-plastic-show] > :not(.c-plastic-under) { position: relative; }
.c-plastic > .c-plastic-under {
  display: none;
  position: absolute; inset: 0;
  overflow: hidden;
  border-radius: inherit;
}
.c-plastic > .c-plastic-under > * {       /* the copy; the page sets its offset and size */
  position: absolute;
  background: var(--paper);
  filter: var(--plastic-backdrop);
}
.c-plastic > .c-plastic-under::after {
  content: "";
  position: absolute; inset: 0;
  background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-frost);
}
.c-plastic.on-deep > .c-plastic-under::after, .c-plastic.on-ink > .c-plastic-under::after, .c-plastic.on-4 > .c-plastic-under::after {
  background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-frost-on-deep);
}

@media print {
  .c-plastic {
    background: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow: none;
  }
  .c-plastic::before {                    /* fill + grain + shadow, behind the content; the only raster */
    content: "";
    position: absolute; inset: 0;
    z-index: -1;
    border-radius: inherit;
    background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-print-fill-on-0);
    filter: var(--plastic-shadow-print);
  }
  .c-plastic.on-deep::before {
    background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-print-fill-on-deep);
  }
  .c-plastic.on-ink::before {             /* over an ink field (CMF round 7) */
    background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-print-fill-on-ink);
  }
  .c-plastic.on-4::before {               /* deprecated: over concrete-4, for archives and cmf.html */
    background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-print-fill-on-4);
  }
  .c-plastic[data-plastic-show] > .c-plastic-under { display: block; }
}

/* --- The live button: electric fill, electric inked edge, no glow ---
   Aaron, 30 Oct: "the live buttons should be electric edge lit" (plastic round 2's lit Edge-lit,
   archived in studio-system/archive/2026-10-30-plastic-studies-round2.html); then, 31 Oct, CMF
   round 7: "the glow effect on the live button can come off". Nothing in the system glows (ban 7,
   no exception; rules.md 5.3). The glow version is archived in
   studio-system/archive/2026-10-31-components-pre-r7.css and 2026-10-31-live-button-pre-r7/.

   Use: class="c-button-live" on the one main action in a view (an <a href> or <button>). It takes
   no focus ring: its electric edge is its edge, focused or not (rules.md 5.2, 5.3; Aaron, 4 Nov
   2026: a ring around a filled, outlined button does not look good). In forced-colours mode it
   keeps a Highlight focus ring, drawn in the ink hand (the block after its print rule). The
   current nav item, the focus ring, a decision point and the progress readout are plain
   electric too (Ban 3: one live thing per view). It never sits on a
   deep-blue field (electric on deep is 1.96:1, ban 6), so it has no dark variant: its .on-4
   variant (over concrete-4) left with concrete-4 on 31 Oct and is kept only as a deprecated
   alias for archives.

   Body: a solid electric fill (Aaron, 31 Oct: "the live buttons should also have an electric blue fill"; it
   replaces the F2 frost body). Square corners and no shadow (Aaron, 31 Oct, CMF round 6): the rounded corner
   and the contact shadow belong to plastic only (ban 16, ban 15), so the button takes neither. Label: the
   display face, bold, at --size-h2, sentence case, in --button-live-label, paper (Aaron, 31 Oct; 3.57:1 on
   electric, so the label must stay large-text size, ban 4's one exception). The squircle version is archived
   in studio-system/archive/2026-10-31-components-pre-r6.css.
   Edge: a baked image from tools/studio/build/build_live_button.py on ::before, the button's own size:
   live-button/edge.svg (the closed rectangle inked in the ink hand, in electric). A plain image, so it
   prints as drawn. ::after is unused (the live button takes no focus ring). One size (--button-live-w x --button-live-h):
   another size needs its asset.

   Print: the fill prints solid electric; the edge is unchanged.
   ---------------------------------------------------------------- */
.c-button-live {
  position: relative; box-sizing: border-box; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--button-live-w); height: var(--button-live-h);
  padding: 0 var(--space-4);
  color: var(--button-live-label); text-decoration: none; white-space: nowrap;
  font-family: var(--font-sans); font-weight: var(--weight-bold); font-size: var(--size-h2);
  line-height: var(--leading-heading); letter-spacing: var(--tracking-heading); text-transform: none;
  background: var(--electric);
}
.c-button-live.on-4 {                    /* deprecated (31 Oct): archives and cmf.html only */
  color: var(--paper);
  background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-frost-on-4);
}
.c-button-live::before {                  /* the electric edge, baked; behind the label. No glow (ban 7) */
  content: "";
  position: absolute; z-index: -1; pointer-events: none;
  inset: 0;
  background: url("live-button/edge.svg") 0 0 / 100% 100% no-repeat;
}
@media print {
  .c-button-live {
    background: var(--electric);     /* the fill prints solid electric */
  }
  .c-button-live.on-4 {                  /* deprecated */
    background: url("plastic-studies/grain-f2.png") 0 0 / var(--plastic-grain-size) var(--plastic-grain-size), var(--plastic-print-fill-on-4);
  }
}

/* Forced colours: the visitor's colours replace the design, and the UA outline is off (:focus-visible, below), so the
   focused live button keeps a focus ring there (rules.md 5.2): the .ink-focus ring, an inked bold frame 3 px
   outside, in Highlight, drawn on the ::after the button leaves free. */
@media (forced-colors: active) {
  .c-button-live:focus-visible {
    --ink-offset: calc(var(--focus-offset) + var(--line-bold) / 2);
    --ink-h0: var(--ink-rule-h-bold-a-start); --ink-h1: var(--ink-rule-h-bold-a-end);
    --ink-h2: var(--ink-rule-h-bold-b-start); --ink-h3: var(--ink-rule-h-bold-b-end);
    --ink-v0: var(--ink-rule-v-bold-a-start); --ink-v1: var(--ink-rule-v-bold-a-end);
    --ink-v2: var(--ink-rule-v-bold-b-start); --ink-v3: var(--ink-rule-v-bold-b-end);
  }
  .c-button-live:focus-visible::after {
    content: "";
    position: absolute; pointer-events: none;
    inset: calc(-1 * (var(--ink-offset) + var(--ink-rule-pad)));
    background-color: Highlight;
    -webkit-mask-image: var(--ink-h0), var(--ink-h1), var(--ink-h2), var(--ink-h3), var(--ink-v0), var(--ink-v1), var(--ink-v2), var(--ink-v3);
    mask-image: var(--ink-h0), var(--ink-h1), var(--ink-h2), var(--ink-h3), var(--ink-v0), var(--ink-v1), var(--ink-v2), var(--ink-v3);
    -webkit-mask-position: left top, right top, left bottom, right bottom, left top, left bottom, right top, right bottom;
    mask-position: left top, right top, left bottom, right bottom, left top, left bottom, right top, right bottom;
    -webkit-mask-size:
      calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
      calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
      var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)),
      var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap));
    mask-size:
      calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
      calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
      var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)),
      var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap));
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
  }
}

/* --- The two surfaces: paper and concrete-1 ---------------------------
   Structure is carried by the material, not by block shapes (Aaron,
   30 Oct; tokens.css, "Concrete as a cast surface"): tie-hole formwork
   panels, a cast surface, seams that weep. One texture only (Aaron,
   31 Oct: "there should only be one concrete texture. just concrete 1"),
   then two surfaces only (Aaron, 31 Oct: "just concrete-1"): paper and
   concrete-1. Depth comes from paper fields, deep-blue fields and
   plastic panels, not from extra greys. The masses .c-block, .c-slab,
   .c-plinth, .c-slit, .c-slot and .c-reveal are retired, archived in
   studio-system/archive/2026-10-30-components-pre-redo.css.

     .c-paper        flat, never textured (formerly .c-concrete-0, 31 Oct). The page
                     background outside a sheet's border, and light fields inside it,
                     the way deep blue holds a dark one. Ink text; signals sit on it
     .c-concrete-1   the ONLY textured surface: the sheet's ground inside its border.
                     Ink text (2.53:1 for electric: no signal on it)

   Never a surface on the same surface (no concrete-1 on concrete-1, no
   paper on paper). .c-concrete-1 sets the token colour (it shows until
   the tile loads, and is the tile's mean) and the production tile from
   concrete-texture/, built by tools/studio/build/build_concrete_texture.py:
   1x by default, 2x through image-set() on high-DPR screens; seamless,
   shown at --concrete-tile-w x --concrete-tile-h and repeated. The tile
   starts at the element's own top left. A plain background image: it
   prints as drawn (print-color-adjust: exact on the page). Text on it is
   judged at the tile's 1st/99th percentile, non-text on its mean; flat
   surfaces exactly (tokens.css rulings). No border, no radius, no shadow.

   Deprecated: .c-concrete-0 is an alias of .c-paper; .c-concrete-2, -3
   and -4 (flat greys that left the system on 31 Oct) keep their old
   fill. All four are kept only so old studies, archives and cmf.html
   still render; check_tokens.py fails them on any other page.
   ---------------------------------------------------------------- */
.c-paper, .c-concrete-0 { background-color: var(--paper); background-image: none; color: var(--ink); }   /* flat, like ink: never textured */
.c-concrete-1 { background-color: var(--concrete-1); color: var(--ink);
  background-repeat: repeat; background-position: 0 0;
  background-size: var(--concrete-tile-w) var(--concrete-tile-h);
  background-image: url("concrete-texture/concrete-c1@1x.png");
  background-image: image-set(url("concrete-texture/concrete-c1@1x.png") 1x, url("concrete-texture/concrete-c1.png") 2x); }
.c-concrete-2 { background-color: var(--concrete-2); background-image: none; }                          /* DEPRECATED (31 Oct) */
.c-concrete-3 { background-color: var(--concrete-3); background-image: none; color: var(--paper); }    /* DEPRECATED (31 Oct) */
.c-concrete-4 { background-color: var(--concrete-4); background-image: none; color: var(--paper); }    /* DEPRECATED (31 Oct) */

/* --- Ink rules: every line in the ink hand ------------------------
   Rule (banned.md, Aaron 30 Oct): no plain CSS border, outline or
   underline, and no raw SVG stroke. Every line in the system is drawn
   in the ink hand (tokens.css, "Ink hand"). SVG drawings are inked by
   tools/studio/ink_hand.py; HTML lines use these classes. Each draws
   its line as a mask over a pre-inked asset (ink-rules.css), cut to
   the element's length, never stretched or tiled; the colour is a
   background, so one asset serves ink, paper, concrete-1 and both blues.

   The element must be positioned (relative or absolute) for the
   pseudo-element classes. Lines are centred on the element's edge;
   --ink-offset moves them out (positive) or in (negative).

     .ink-frame        four edges, ::after. Corners are joins: the
                       pooled ends of the two edges meet there.
                       Serves: sheet frames, tile and swatch edges,
                       table and panel boxes, the focus ring.
     .ink-edge-top     one rule along the top edge, ::before.
     .ink-edge-bottom  one rule along the bottom edge, ::after.
                       Serve: row rules, key-value separators, table
                       rules, underlines (current link), the active
                       row's signal rule.
     .ink-rule         the element IS the rule (a divider or progress
                       line): --ink-rule-box high, both ends pooled.
     .ink-pill         a capsule outline, ::after; the element is 20 px
                       high. Serves: the Don't tag, small labels.
     edges             .c-plastic::after above: the panel's rim and far
                       edge, baked images (no mask, no print swap).

     .ink-rim          the plastic rim on any element, ::before, as a
                       mask in --plastic-edge (print-proof.html); .c-plastic
                       carries its own two edges.
     .ink-focus        the focus ring: an inked bold frame in electric,
                       --focus-offset outside the part, on
                       :focus-visible (and always with .is-focus, for a
                       specimen). ::after. The UA outline is off.

   Weight: .ink-hair (default; rules, frames, the key-value head rule),
   .ink-fine, .ink-bold, .ink-dash (dashed: construction only, rules.md
   3.2; CMF round 7 moved the key-value head rule from dash to hair).
   Tone (the colour, always set as a class, never as --ink-color by
   hand): .ink-ink, .ink-paper (lines on a deep field), .ink-c1,
   .ink-deep, .ink-electric. Lines that were concrete-2 are ink at the
   right weight (rules.md 3.2). Deprecated, for old studies, archives
   and cmf.html only (check_tokens.py fails them elsewhere): .ink-c0
   (an alias of .ink-paper), .ink-c2 and .ink-c3 (concrete-2 and -3,
   which left the system on 31 Oct). Signal lines (the active row, the current link, the
   focus ring, progress) are .ink-electric. With no tone class the line
   takes currentColor on screen.
   Length: a line, or a frame's drawing box (the element plus
   2 x (--ink-rule-pad + --ink-offset)), may be up to --ink-rule-max-h
   across and --ink-rule-max-v down; past that the assets would scale.
   tools/studio/shoot.py fails a sheet with a longer one.
   Print: macOS Quartz (Preview, Quick Look) draws Chromium's PDF masks
   only in the page's top-left corner, so on paper every mask swaps for
   the same drawing with its tone baked in (ink-rules-print.css, loaded
   for print only). Baked sets exist for the tone and weight pairs in
   tools/studio/ink_rules.py (PRINT_SETS). check_tokens.py fails a page
   that uses an ink line with no tone class, or a pair that the linked
   ink-rules-print.css lacks: add it to PRINT_SETS and re-run.
   ---------------------------------------------------------------- */
.ink-frame, .ink-edge-top, .ink-edge-bottom, .ink-rule, .ink-pill, .ink-focus {
  --ink-color: currentColor;
  --ink-offset: 0px;
  --ink-h0: var(--ink-rule-h-hair-a-start); --ink-h1: var(--ink-rule-h-hair-a-end);
  --ink-h2: var(--ink-rule-h-hair-b-start); --ink-h3: var(--ink-rule-h-hair-b-end);
  --ink-v0: var(--ink-rule-v-hair-a-start); --ink-v1: var(--ink-rule-v-hair-a-end);
  --ink-v2: var(--ink-rule-v-hair-b-start); --ink-v3: var(--ink-rule-v-hair-b-end);
}
.ink-fine {
  --ink-h0: var(--ink-rule-h-fine-a-start); --ink-h1: var(--ink-rule-h-fine-a-end);
  --ink-h2: var(--ink-rule-h-fine-b-start); --ink-h3: var(--ink-rule-h-fine-b-end);
  --ink-v0: var(--ink-rule-v-fine-a-start); --ink-v1: var(--ink-rule-v-fine-a-end);
  --ink-v2: var(--ink-rule-v-fine-b-start); --ink-v3: var(--ink-rule-v-fine-b-end);
}
.ink-bold {
  --ink-h0: var(--ink-rule-h-bold-a-start); --ink-h1: var(--ink-rule-h-bold-a-end);
  --ink-h2: var(--ink-rule-h-bold-b-start); --ink-h3: var(--ink-rule-h-bold-b-end);
  --ink-v0: var(--ink-rule-v-bold-a-start); --ink-v1: var(--ink-rule-v-bold-a-end);
  --ink-v2: var(--ink-rule-v-bold-b-start); --ink-v3: var(--ink-rule-v-bold-b-end);
}
.ink-dash { --ink-h0: var(--ink-rule-h-fine-dash); --ink-h1: none; --ink-h2: var(--ink-rule-h-fine-dash); --ink-h3: none; }

.ink-focus {
  position: relative;
  --ink-color: var(--electric);
  --ink-offset: calc(var(--focus-offset) + var(--line-bold) / 2);
  --ink-h0: var(--ink-rule-h-bold-a-start); --ink-h1: var(--ink-rule-h-bold-a-end);
  --ink-h2: var(--ink-rule-h-bold-b-start); --ink-h3: var(--ink-rule-h-bold-b-end);
  --ink-v0: var(--ink-rule-v-bold-a-start); --ink-v1: var(--ink-rule-v-bold-a-end);
  --ink-v2: var(--ink-rule-v-bold-b-start); --ink-v3: var(--ink-rule-v-bold-b-end);
}
:focus-visible { outline: none; }        /* the ring is .ink-focus, never the UA outline */

.ink-paper, .ink-c0 { --ink-color: var(--paper); }   /* .ink-c0: deprecated alias */
.ink-c1       { --ink-color: var(--concrete-1); }
.ink-c2       { --ink-color: var(--concrete-2); }   /* DEPRECATED (31 Oct) */
.ink-c3       { --ink-color: var(--concrete-3); }   /* DEPRECATED (31 Oct) */
.ink-ink      { --ink-color: var(--ink); }
.ink-deep     { --ink-color: var(--deep); }
.ink-electric { --ink-color: var(--electric); }

.ink-frame::after, .ink-focus:focus-visible::after, .ink-focus.is-focus::after {
  content: "";
  position: absolute; pointer-events: none;
  inset: calc(-1 * (var(--ink-offset) + var(--ink-rule-pad)));
  background-color: var(--ink-color);
  -webkit-mask-image: var(--ink-h0), var(--ink-h1), var(--ink-h2), var(--ink-h3), var(--ink-v0), var(--ink-v1), var(--ink-v2), var(--ink-v3);
  mask-image: var(--ink-h0), var(--ink-h1), var(--ink-h2), var(--ink-h3), var(--ink-v0), var(--ink-v1), var(--ink-v2), var(--ink-v3);
  -webkit-mask-position: left top, right top, left bottom, right bottom, left top, left bottom, right top, right bottom;
  mask-position: left top, right top, left bottom, right bottom, left top, left bottom, right top, right bottom;
  -webkit-mask-size:
    calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
    calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
    var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)),
    var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap));
  mask-size:
    calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
    calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
    var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)),
    var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap));
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.ink-edge-top::before, .ink-edge-bottom::after, .ink-rule {
  background-color: var(--ink-color);
  -webkit-mask-image: var(--ink-h0), var(--ink-h1);
  mask-image: var(--ink-h0), var(--ink-h1);
  -webkit-mask-position: left center, right center;
  mask-position: left center, right center;
  -webkit-mask-size: calc(50% + var(--ink-rule-overlap)) 100%;
  mask-size: calc(50% + var(--ink-rule-overlap)) 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.ink-dash.ink-edge-top::before, .ink-dash.ink-edge-bottom::after, .ink-dash.ink-rule {
  -webkit-mask-size: auto 100%;
  mask-size: auto 100%;
}
.ink-edge-top::before, .ink-edge-bottom::after {
  content: "";
  position: absolute; pointer-events: none;
  left: 0; right: 0;
  height: var(--ink-rule-box);
}
.ink-edge-top::before    { top: calc(-1 * (var(--ink-offset) + var(--ink-rule-pad))); }
.ink-edge-bottom::after  { bottom: calc(-1 * (var(--ink-offset) + var(--ink-rule-pad))); -webkit-mask-image: var(--ink-h2), var(--ink-h3); mask-image: var(--ink-h2), var(--ink-h3); }
.ink-rule { display: block; height: var(--ink-rule-box); }

.ink-pill { box-sizing: border-box; height: calc(var(--ink-rule-box) * 2.5); }   /* 20 px: the capsule asset's height */
.ink-pill::after {
  content: "";
  position: absolute; pointer-events: none;
  inset: calc(-1 * var(--ink-rule-pad));
  background-color: var(--ink-color);
  -webkit-mask-image: var(--ink-rule-pill-fine-start), var(--ink-rule-pill-fine-end);
  mask-image: var(--ink-rule-pill-fine-start), var(--ink-rule-pill-fine-end);
  -webkit-mask-position: left center, right center;
  mask-position: left center, right center;
  -webkit-mask-size: calc(50% + var(--ink-rule-overlap)) 100%;
  mask-size: calc(50% + var(--ink-rule-overlap)) 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.ink-rim { position: relative; }
.ink-rim::before {
  content: "";
  position: absolute; inset: 0; pointer-events: none;
  background-color: var(--plastic-edge);
  -webkit-mask: var(--ink-rule-rim) left top / auto no-repeat;
  mask: var(--ink-rule-rim) left top / auto no-repeat;
}

/* Print: the masks swap for the baked drawings (see above). */
@media print {
  .ink-frame, .ink-edge-top, .ink-edge-bottom, .ink-rule, .ink-pill, .ink-focus {
    --ink-ph0: var(--ink-p-hair-h0); --ink-ph1: var(--ink-p-hair-h1); --ink-ph2: var(--ink-p-hair-h2); --ink-ph3: var(--ink-p-hair-h3);
    --ink-pv0: var(--ink-p-hair-v0); --ink-pv1: var(--ink-p-hair-v1); --ink-pv2: var(--ink-p-hair-v2); --ink-pv3: var(--ink-p-hair-v3);
  }
  .ink-fine {
    --ink-ph0: var(--ink-p-fine-h0); --ink-ph1: var(--ink-p-fine-h1); --ink-ph2: var(--ink-p-fine-h2); --ink-ph3: var(--ink-p-fine-h3);
    --ink-pv0: var(--ink-p-fine-v0); --ink-pv1: var(--ink-p-fine-v1); --ink-pv2: var(--ink-p-fine-v2); --ink-pv3: var(--ink-p-fine-v3);
  }
  .ink-bold, .ink-focus {
    --ink-ph0: var(--ink-p-bold-h0); --ink-ph1: var(--ink-p-bold-h1); --ink-ph2: var(--ink-p-bold-h2); --ink-ph3: var(--ink-p-bold-h3);
    --ink-pv0: var(--ink-p-bold-v0); --ink-pv1: var(--ink-p-bold-v1); --ink-pv2: var(--ink-p-bold-v2); --ink-pv3: var(--ink-p-bold-v3);
  }
  .ink-dash { --ink-ph0: var(--ink-p-h-fine-dash); --ink-ph1: none; --ink-ph2: var(--ink-p-h-fine-dash); --ink-ph3: none; }

  .ink-frame::after, .ink-focus:focus-visible::after, .ink-focus.is-focus::after,
  .ink-edge-top::before, .ink-edge-bottom::after, .ink-rule, .ink-pill::after, .ink-rim::before {
    -webkit-mask: none; mask: none;
    background-color: transparent;
    background-repeat: no-repeat;
  }
  .ink-frame::after, .ink-focus:focus-visible::after, .ink-focus.is-focus::after {
    background-image: var(--ink-ph0), var(--ink-ph1), var(--ink-ph2), var(--ink-ph3), var(--ink-pv0), var(--ink-pv1), var(--ink-pv2), var(--ink-pv3);
    background-position: left top, right top, left bottom, right bottom, left top, left bottom, right top, right bottom;
    background-size:
      calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
      calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box), calc(50% + var(--ink-rule-overlap)) var(--ink-rule-box),
      var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)),
      var(--ink-rule-box) calc(50% + var(--ink-rule-overlap)), var(--ink-rule-box) calc(50% + var(--ink-rule-overlap));
  }
  .ink-edge-top::before, .ink-rule {
    background-image: var(--ink-ph0), var(--ink-ph1);
    background-position: left center, right center;
    background-size: calc(50% + var(--ink-rule-overlap)) 100%;
  }
  .ink-edge-bottom::after {
    background-image: var(--ink-ph2), var(--ink-ph3);
    background-position: left center, right center;
    background-size: calc(50% + var(--ink-rule-overlap)) 100%;
  }
  .ink-dash.ink-edge-top::before, .ink-dash.ink-edge-bottom::after, .ink-dash.ink-rule { background-size: auto 100%; }
  .ink-pill::after {
    background-image: var(--ink-p-pill-fine-start), var(--ink-p-pill-fine-end);
    background-position: left center, right center;
    background-size: calc(50% + var(--ink-rule-overlap)) 100%;
  }
  .ink-rim::before { background-image: var(--ink-p-rim); background-position: left top; }
}
