/* ═══ THE SYSTEM'S TOKENS ═══════════════════════════════════════════════════
   THIS FILE IS THE SOURCE. The reference page at docs/design-system.html no longer
   holds a second copy of these: `npm run system:sync` writes them into its <style>
   between the markers, so the page is a SPECIMEN of the rules rather than a copy
   that agrees with them today. A published artifact admits no external stylesheet,
   which is why the page carries the bytes rather than a link.

   Every token is defined here on bare :root as the LIGHT set. Dark redefines only
   the values, twice — once behind prefers-color-scheme for the viewers who never
   chose, once behind [data-theme] for the ones who did. No component rule anywhere
   may name a colour that is not one of these.

   THE TOKENS ARE THE PRODUCT'S, not one app's: the web app and the landing page both
   read this file, so the two cannot drift into two palettes. A page that needs a value
   of its own (the landing page's widths, its glow) names it in its own sheet. The
   component rules shared across the web app's screens are in
   `apps/web/src/styles/system.css`. */

:root{
  /* The platform's own furniture — a scrollbar, a date picker, a caret — follows
     the theme instead of arriving white in a dark app. */
  color-scheme:light;
  /* ── ground, ink, line ───────────────────────────────────────────────
     Neutrals biased toward the accent: a cool paper, not a warm cream. */
  --ground:      #EDF0F2;
  --raised:      #FFFFFF;
  --sunken:      #E1E6EA;
  --line:        #D3DADF;
  --line-strong: #AFBBC3;
  --ink:         #12171B;
  --ink-quiet:   #4B565E;
  /* THE FAINT INK IS MEASURED AGAINST THE SUNKEN GROUND, not the page's.
     #636F77 passed on paper (4,99:1) and on a card (5,71:1) and failed exactly
     where it does its work — on the well, the chip and the disabled control,
     all of which are SUNKEN: 4,10:1, thirteen elements in the light theme. An
     ink is only as good as the darkest ground it is allowed to sit on. */
  --ink-faint:   #5D6870;
  /* CYAN. Chosen over the blue this sheet opened with, and measured before it was
     chosen: 6,03:1 on paper, 5,25:1 for its neighbour, and 4,80:1 on the SUNKEN
     ground, which is the darkest ground an accent is allowed to sit on here. */
  --accent:      #0B6C82;
  --accent-soft: #E0F1F3;
  --on-accent:   #FFFFFF;
  --focus:       #0B6C82;
  /* THE SECOND ACCENT, AND IT IS NAMED AS ONE. It was `--deload`, which is one of the things
     it describes rather than what it is — so every other member the rule below invites would
     have arrived under the name of the first. WHICH ACCENT WHEN is a rule, stated in 02: the
     accent POINTS and this one DESCRIBES. The accent follows the reader — tap another tab,
     another day, another chip and it moves. This one does not move when the reader
     moves, because it is about the PLAN: what the plan asks for differently over a
     stretch of time. Today that has one member, a lighter training, drawn in three
     places; the rule says who else may join it.

     IT ONCE SHARED A HUE WITH `--pending`, and the fix was to move pending to
     copper rather than to bend the yellow: ΔE 32,0 in light and 39,1 in dark, where
     the old pair was 16,5. The hatch stays anyway — a light training is HATCHED and
     pending is a solid stripe — because hue separation is not a carrier for
     everyone, and this system never leaves a fact to colour alone. */
  --accent-2:      #7D6B00;

  /* ── THE HATCH, WHICH IS HOW A LIGHTER TRAINING IS DRAWN ──────────────
     The rule above says a light training is HATCHED and pending is a solid stripe, and the
     reference page had the only copy of the recipe — so the app said "deload" in a word
     instead, in whichever component happened to need it. One recipe, named here, and every
     surface that has to say it says it the same way.

     TWO OF THEM, BECAUSE THE SAME FACT MEETS TWO GROUNDS. Where the deload's own colour is
     free, the hatch carries it and the fact is findable at a glance down a month. Where it is
     spoken for — the week strip paints the day you are reading in exactly this yellow — the
     hatch is drawn in the ink of the surface instead, and the SHAPE is what says it. Neither
     is a fill: both are laid over whatever ground the thing already has.

     THE STRIPE IS `--edge`, the width this system already names for a mark that says WHAT KIND
     of thing something is. */
  /* SIX AND SIXTEEN, MEASURED ON THE SURFACE IT COVERS MOST OF. At ten and twenty-six it was
     right on a badge and a wall on a card's whole top band: the same stripe reads twice as loud
     over four hundred pixels as over sixty, and what a hatch owes is to be seen rather than to
     be the thing you see. */
  --hatch-deload: repeating-linear-gradient(135deg,
    color-mix(in srgb, var(--accent-2) 6%, transparent) 0 var(--edge),
    color-mix(in srgb, var(--accent-2) 16%, transparent) var(--edge) calc(var(--edge) * 2));
  --hatch-quiet: repeating-linear-gradient(135deg,
    transparent 0 var(--edge),
    color-mix(in srgb, var(--ink) 10%, transparent) var(--edge) calc(var(--edge) * 2));

  /* ── THE RING A ROUTINE'S COLOUR LANDS ON ────────────────────────────
     A ROUTINE'S COLOUR IS COMPUTED, NOT NAMED, because there is no number
     of routines to name colours for. The five plate colours were doing this
     job and could not: five hues against an unbounded set, and each of them
     already meaning a weight of iron, so the colour said something false
     about the routine before it said anything true.

     ONLY THE HUE IS COMPUTED. The lightness and the chroma are the theme's,
     and they are these two numbers, so every routine weighs the same as
     every other and none of them outweighs a refusal. They are not invented:
     measured in OKLCH, the five tones this system already reasons in —
     accent, kept, refused, pending, deload — sit at L 0,482–0,529 and
     C 0,086–0,148 in this theme. The ring is their middle.

     AND OKLCH RATHER THAN HSL, because a fixed lightness in HSL is not a
     fixed lightness: yellow at L30 reads far lighter than blue at L30, and
     "every routine at one weight" would have been false by construction.
     Where a hue cannot reach this chroma inside sRGB the browser brings it
     back in gamut, which costs a little colour and never the weight. */
  --tone-l: 0.50;
  --tone-c: 0.11;
  /* THE SECOND ACCENT HAD NO GROUND. The first has `--accent-soft` to be laid on;
     the yellow was only ever ink and a rail, so nothing could be FILLED with it. */
  --accent-2-soft: #F7F0D4;
  /* AND A GROUND FOR WORK THAT IS FINISHED. It takes the semantic green's hue and is a
     separate token, because `--kept` means written down and on the disk: one colour standing
     for two facts is what a system of this size is for refusing. What it says here is that
     everything a day held was trained — a summary, laid under marks that each say their own
     part — so it is a GROUND and never ink, and it is the palest step the scale allows.

     MEASURED ON IT, both themes: `--ink` 15,2:1 on paper and 13,0:1 in the dark, `--ink-quiet`
     6,3 and 6,8, `--ink-faint` 4,8 — which is the one that decides the value, since a day
     either side of the month is drawn in it and may also be finished. */
  --done-soft:   #DDF0E8;

  /* ── the accent, as a surface ────────────────────────────────────────
     Wherever the accent FILLS something, it fills it with a gradient rather
     than a flat swatch — two stops, one hue, a few per cent apart. Enough
     for the surface to have a top and a bottom; not enough to read as a
     button from 2011. The light comes from above, always, because a screen
     has one light and a page that lights things from different sides looks
     assembled rather than made.

     AND THAT WAS THE WRONG LIGHT. A ramp from lighter to darker of ONE hue,
     running top to bottom, is a bevel — the raised plastic key of 2011 — and
     it arrived here by exactly the route the sheet had already argued against,
     wearing the word "subtle". The eye reads a vertical ramp as a rounded
     FACE; there is no way to make that subtle enough to stop.

     A GRADIENT IS A LIGHT ALONG AN EDGE.

       It runs ACROSS, on a slant, never straight down.
       It runs between TWO NEIGHBOURING HUES, never light-to-dark of one — two
         colours a few degrees apart read as a thing catching the light from
         one side; one colour getting darker reads as a thing bulging.
       It belongs on the EDGE first. A border is one pixel wide, so a gradient
         in it can be much more definite than one on a face and still stay
         quiet — which is why the edge is where this system spends it.

     ONE ANGLE for the whole sheet, or every lit thing points somewhere else
     and the page looks assembled rather than made. */
  --sweep: 115deg;

  /* THE NEIGHBOUR, AND IT IS NOT THE SECOND ACCENT. It was called `--accent-2`, which is
     what a reader would take the second accent to be — and the second accent is the yellow
     above, which was called `--deload` after one of the things it describes. Two names, both
     saying something other than what they hold. This one is the accent's own hue with a light
     on it, spent by the sweep and by nothing that means anything.

     THE ACCENT'S SECOND COLOUR, a short step around the wheel — far enough that the sweep is
     visible, near enough that it is still the same colour with a light on it.

     AND IT IS HELD TO THE SAME CONTRAST AS THE ACCENT ITSELF. A sweep means
     the label stands on BOTH stops, so the weaker one is the one that counts:
     the first choice here, #0E7FB8, measured 4,42:1 against white — a button
     that passed at one end of itself and failed at the other. */
  --accent-lit:    #0B7787;
  /* The edge, lit. Quiet for anything with an ordinary border; accent for a
     thing that is chosen, focused, or the one act of the screen. */
  --edge-quiet:  linear-gradient(var(--sweep),
      var(--line-strong) 0%, var(--line) 48%, var(--line-strong) 100%);
  --edge-accent: linear-gradient(var(--sweep), var(--accent-lit), var(--accent));
  --edge-soft:   linear-gradient(var(--sweep),
      color-mix(in srgb, var(--accent) 45%, var(--line)) 0%, var(--line) 70%);
  /* The few things that are FILLED with the accent take the same two hues,
     the same way across. */
  --fill-accent: linear-gradient(var(--sweep), var(--accent), var(--accent-lit));

  /* ── the plate set: CATEGORICAL, never semantic ──────────────────────
     Competition plates. A lifter reads these as weights without thinking,
     which is why they are the app's code for a routine, a muscle group, a
     band of load. Red never means "wrong" here. */
  --plate-25: #C8102E;
  --plate-20: #0067B1;
  --plate-15: #E8B500;
  --plate-10: #00873E;
  --plate-5:  #8C979E;

  /* ── the semantic three, and only three ──────────────────────────────
     Separate from the accent and from the plates. */
  --refused: #A3342B;   /* an act the app would not perform */
  --kept:    #0B6E5B;   /* written down, and it reached the disk */
  /* COPPER, NOT AMBER — and the reason is the instrument, not the hue. This sat at
     #8A5A00 and the light training's yellow measured 1,14:1 against it, which was read
     here as a collision. It is not the number to ask: a contrast RATIO compares
     LUMINANCE, so two hues at one lightness always read 1:1 however different they
     look. Asked in Lab, where the question belongs: the old pair was ΔE 16,5 — a
     shade of the same colour — and copper against the same yellow is ΔE 32,0 in
     light and 39,1 in dark, which is two colours.
     The tightest pair in this set is now copper against the refusal, ΔE 21,9; both
     carry their own word, which is what the sentence component is for. */
  --pending: #9C4F17;   /* written and not yet sent */
  /* EXERCISES DONE IN TURN - a superset, a circuit. Violet, the one hue nothing else here holds:
     the accent is the act and the row whose turn it is, yellow the day's own answers, green done,
     red and orange the state of a write, and blue sits too near the accent to be told from it.
     Measured against the darkest ground it stands on: 4,88:1 on the sunken ground here, 7,31:1
     in the dark theme. */
  --together: #6E48C8;

  /* ── type: TWO REGISTERS, and every piece of text is in one of them ──
     The division is not decorative. It says who wrote the thing.

       THE HUMAN REGISTER is proportional, and sentence-cased. It is what a
       person wrote or would say: a heading, the name of an exercise, a
       paragraph, the line under a figure explaining where it came from.
         Archivo  names and headings — an engineered grotesque, set expanded
         Barlow   what is read — narrow enough to stay dense at 14px

       THE MACHINE REGISTER is monospace and UPPER CASE. It is what the app
       states or performs: a figure, a unit, a window, the label naming what a
       value IS — and the word on a control, because a control names an ACT
       THE APP WILL CARRY OUT.
         Chivo Mono  Omnibus-Type, like Archivo — the pairing is by
                     construction rather than by luck. Chosen over JetBrains
                     Mono, IBM Plex Mono and DM Mono; the comparison is 04.

     UPPER CASE COMES FROM `text-transform`, NEVER FROM THE WORDS THEMSELVES.
     The source keeps ordinary sentence case, so the same string can be read
     aloud, searched, or sent to an agent without shouting; the screen raises
     it. And `capitalize` is not the middle ground it looks like: it raises
     EVERY word, which in Polish puts "Dodaj Serię" on a button.

     AN IDENTIFIER IS NEVER TRANSFORMED. `wlt_9c2f…a71e`,
     `barbell-bench-press`, `--ink-faint`, `aria-busy` are case-SENSITIVE —
     raising them would print a string that does not exist. They are machine
     register and they stay exactly as the machine writes them, which is why
     `.mono`, `.id`, `code` and the token columns are excluded by name. */
  --face-name: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --face-read: 'Barlow', 'Helvetica Neue', Arial, sans-serif;
  --face-data: 'Chivo Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --t-page:    22px;   /* the page's own name */
  --t-section: 17px;   /* a section of it */
  --t-part:    14px;   /* a part of a section — body size, heavier */
  --t-body:    14px;   /* what is read */
  --t-detail:  12.5px; /* what stands beside it */
  --t-label:   10.5px; /* what a value IS — mono, tracked, quiet */
  /* A LETTER INSIDE A MARK, and the one size on this scale that is not read as language. It
     names ONE character and is never given a word.

     IT USES THE HOLE IT HAS. Eight was set against a 12px circle with a two-pixel ring, which
     left eight of hole for a capital standing 5,7. The mark is 14 now and its ring is a
     hairline, so the hole is twelve and that same letter sat in it with three pixels of air on
     every side — small for a reason that had stopped applying. At ten the capital stands 7 and
     keeps two and a half, and the disc does not move, so a cell still holds the three marks it
     held. It stays UNDER `--t-label`: the size below language is what says this is a mark
     rather than a word, and that is a rule about rank, not about pixels. */
  --t-mark:    10px;
  --t-figure:  30px;   /* a reading's own number */
  /* AND A FIELD IS SIXTEEN, whatever the body is. Below 16px iOS Safari zooms
     the whole page when the field takes focus, and it does not zoom back — the
     person is left panning a log they were in the middle of typing into. The
     body is 14; a field is the one thing that may not follow it. */
  --t-input:   16px;
  --t-figure-lg: 42px; /* the one figure a screen is opened for */

  /* WEIGHT WAS FIVE LITERALS. A role said "body size, heavier" and nothing said
     by how much, so 400, 500, 600, 700 and 800 were chosen at the rule. */
  --w-read:  400;   /* what is read */
  --w-mark:  500;   /* a value inside a line of data */
  --w-part:  600;   /* a part of a section — the rank carried by weight, not size */
  --w-name:  700;   /* a name, a heading, a figure */
  --w-page:  800;   /* the page's own name, and nothing else */

  --lead-tight: 1.1;    /* a figure, standing alone */
  --lead-flat:  1.25;   /* a heading, a row of one or two lines */
  --lead-read:  1.5;    /* a paragraph */
  /* AND THREE THAT ARE NOT READING AT ALL. A leading was a bare number wherever a box held a mark
     rather than a line of text — a letter in a badge, a unit in a well, a figure in a tile — and
     each was chosen at the rule, the way the weights once were. */
  --lead-tile:  1.05;   /* a figure over the word that names it, in a row of such tiles */
  --lead-mark:  1;      /* a mark or a single character: the box is the glyph */
  --lead-none:  0;      /* a box holding a drawing and no text: no line box of its own */

  /* Tracking, and it exists BECAUSE of the upper case. Capitals sit tight
     against each other and are read as shapes rather than as a word; the
     room is what makes a raised label legible at 10,5px. Two values, because
     a 10,5px label needs more of it than a 14px control. */
  --track-label: .12em;
  --track-caps:  .06em;
  /* A LINE OF CAPITALS HAS NO DESCENDERS, so a box padded equally looks padded
     unequally: the space above the caps is the room between the ascender and
     the cap-height, and the space below is the whole descender — empty, and
     roughly twice as deep. The text rides high and the top gap reads as too
     small. This is the one pixel that gives it back, and it is a TOKEN so that
     the compensation is the same everywhere rather than eyeballed per box. */
  --cap-drop: 1px;
  --track-page: -.02em;

  /* ── interaction ─────────────────────────────────────────────────────
     A state is never carried by COLOUR ALONE — it is a ground, a ring, a
     movement or a mark, and colour comes with it. Somebody who cannot tell
     the accent from the ink still has to know what is focused, what is
     chosen and what will not respond. */
  --lift:  color-mix(in srgb, var(--ink) 6%, transparent);  /* hover: the ground rises */
  --press: 1px;                                             /* active: the thing moves down */
  --ring:  2px;                                             /* focus: a ring, always visible */
  --ring-gap: 2px;
  --chosen-mark: '✓';
  --off-ink: var(--ink-faint);   /* disabled: quiet ink, and a sentence says why */

  /* ── HOW MUCH OF A THING SHOWS ───────────────────────────────────────
     Nothing and all of it are not values — `0` and `1` are the absence and the thing — and
     everything between was a figure chosen at the rule. Each of these is a job. */
  --o-off:   .5;    /* a control that will not answer, with the words that go with it */
  --o-dot:   .55;   /* one reading in a dense run of them, so the run stays a run */
  --o-glow:  .45;   /* a light that only agrees with what already says the thing */
  --o-aside: .78;   /* the controls beside a reading, on a ground of their own */

  /* ── layers ──────────────────────────────────────────────────────────
     Four the page is stacked in, and no fifth. A page that needs a fifth has two
     things fighting for the same job.

     AND TWO THAT ARE NOT THE PAGE'S: a layer under the content of its own box, and
     what hangs off a control over the page and the bars pinned on it. Both were
     bare numbers — `-1` and `2` — beside a scale that named neither. */
  --z-under: -1;    /* under its own box's content, inside a box that isolates it */
  --z-page: 0;
  --z-sticky: 10;   /* a bar that stays while the page moves under it */
  --z-pop: 15;      /* what hangs off a field, over the page and its pinned bars */
  --z-sheet: 20;    /* a layer the page waits behind */
  --z-tip: 30;      /* a word held down over everything */
  /* THE SCRIM IS MADE OF THE THEME'S OWN DARKEST INK, NEVER OF PURE BLACK.
     Black at 45% over a light ground darkens the GROUND a great deal and the
     near-black INK barely at all, so the two converge: the page behind the
     sheet came out a dead grey slab with dark text sitting in it — muddy
     rather than set back, and measured at 2,45:1 for a heading and 1,45:1 for
     a detail. Made of `--ink`, the veil keeps the palette's temperature and
     the page reads as unlit rather than stained.

     AND IT GOES FAR, NOT HALF-WAY. Any veil over a light page pulls the ground
     and the near-black ink toward each other, so contrast falls whatever the
     alpha — the only question is what it LOOKS like. At 45% and at 64% it
     landed in the middle: a slab too dark to be paper and too light to be
     shadow, with legible-but-muddy text sitting in it. At 86% the page reads
     as UNLIT, the sheet's white carries, and nothing looks broken.

     THE TEXT BEHIND IT IS NOT HELD TO A CONTRAST RULE. A page behind a sheet
     is deliberately not for reading; that is what a sheet IS. Written down so
     nobody measures it and "fixes" it back into legibility later. */
  --scrim: color-mix(in srgb, var(--ink) 86%, transparent);
  --shadow-raise: 0 1px 2px color-mix(in srgb, #000 8%, transparent);
  /* THE APP'S ICON TAKES THE THEME: the black square of `favicon.svg` turns white with a black mark
     on a light ground, and is lifted off it by the raised shadow, as a white card is. Dark keeps
     the square as drawn. */
  --icon-invert: 1;
  --shadow-sheet: 0 -2px 24px color-mix(in srgb, #000 22%, transparent);

  /* ── space: the steps ────────────────────────────────────────────────
     Six, and one below them. The first draft said "six and no seventh,
     below four a gap is letter-spacing" — and then used 2px three times,
     3px, 5px twice, 6px twice and a 5×9 padding. Nine values the scale did
     not contain, in one sheet, written in an hour. That is the census this
     kind of scale exists to end, so either the values were wrong or the
     scale was missing a step. It was missing one:

     --s0 is not a gap between two things. It is the space between PARTS OF
     ONE THING — the three lines of an exercise row, a label over the figure
     it names. Those are not two objects a step apart; they are one object,
     and four pixels already reads as a separation. */
  --s0: 2px;
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 36px;

  /* ── space: one token per RELATIONSHIP ───────────────────────────────
     The scale says which gaps exist. These say which gap a relationship
     GETS. The rule is that one relationship never takes two values — two
     relationships MAY share one, and where they do it is said. */
  --gap-within:  var(--s0);   /* parts of one object: a label and its figure */
  --gap-line:    var(--s1);   /* things sitting on one line: a mark and its word */
  --gap-row:     var(--s2);   /* two rows of a list separated by SPACE alone */
  --gap-head:    var(--s3);   /* a heading and the block it heads */
  --gap-block:   var(--s4);   /* two blocks inside a section */
  --gap-section: var(--s6);   /* two sections of a page */
  --pad-row:     var(--s2);   /* above and below the hairline of a ruled list */
  --pad-card:    var(--s3);   /* inside anything with an edge */
  --pad-page:    var(--s4);   /* the page's own margin */

  /* ── THE SIZE A DRAWN MARK TAKES ─────────────────────────────────────
     THE ONE SCALE THIS SYSTEM WAS MISSING, and the audit that found it
     counted the cost: 14, 16, 20 and 22 were sitting as bare numbers in
     five components — a spinner, a meter, the chevron in a step, a tab's
     mark. Every icon in the app was naming its own number, which is the
     definition of a random style even when the number is a good one.

     Three sizes, and each is decided by WHAT HOLDS THE MARK rather than by
     the mark: how much room the control has, and whether the mark is the
     control's whole point or something beside a word. */
  --mk-s: 14px;   /* beside body text, or inside a control that is mostly text */
  --mk:   16px;   /* alone inside a `--tap-tight` control */
  --mk-l: 22px;   /* the control's whole point, with only a label under it */
  /* AND ONE MARK IS DRAWN RATHER THAN IMPORTED: the tick a checkbox wears is two
     borders on an empty box, turned forty-five degrees, so its two arms are the whole
     of its geometry. They are named here because the box it sits in is `--mk-s` and
     these two decide whether the mark reads as a mark or as something pressed against
     a wall — the sizing note beside the rule that draws it has the arithmetic. */
  --tick-long:  6px;
  --tick-short: 3px;
  /* AND ONE THAT IS NOT A DRAWN GLYPH: the calendar's routine mark, a disc carrying a single
     letter. It sits between two steps of the spacing scale on purpose — twelve left the letter
     cramped and sixteen is a size at which two marks stop fitting a cell where three used to.
     A mark that has to hold a character is not a spacing value, so it is named here. */
  --rt:   14px;

  /* ── A RULE IS NOT A MEASURE ─────────────────────────────────────────
     1px and 2px are the only literals a component sheet may carry, and
     they are not exempted for convenience: a hairline is not a length off
     the spacing scale, it is the thinnest mark a screen can draw and the
     one below it. Putting them on the scale as `--s-hair` would say they
     are a small amount of SPACE, which is the one thing they are not.
     `scripts/system-sync.mjs` refuses every other literal. */

  /* ── SEPARATION: A LINE ONLY WHERE SPACE CANNOT DO IT ────────────────
     A rule is allowed in exactly three cases, and space does everything else:

       1 · it is a BOUNDARY between two different kinds of surface —
           a card's head against its body, a sheet against the page it covers;
       2 · it carries ALIGNMENT — a table, where the eye runs down a column
           and the line is what keeps the row it is on readable;
       3 · the two things are the SAME KIND, space alone would be ambiguous,
           and the density does not allow more of it — the rows of a training,
           three stacked lines each, on a phone held between sets.

     Everything else is separated by the ladder above. A line drawn where a gap
     would do is a line that says "these are different things" about two things
     that are not. */

  /* ── corners ─────────────────────────────────────────────────────────
     THE RADIUS FOLLOWS THE SIZE OF THE BOX, not the taste of the rule. A
     small box takes a small corner or it reads as a lozenge; a box with
     content in it takes the one corner everything with an edge takes. Three
     values existed before this and nothing said which thing got which — the
     sheet simply used whichever, and a raw 14px besides. */
  /* SMALLER THAN A FINGER — a swatch, a bar, a cell of the WEEK RAIL, which is a strip of
     blocks a few pixels tall. Anything a finger aims at, with an edge and something written in
     it, is a card by the line below whatever it is called: the calendar's day cell borrowed
     this one on the word "cell" and read as a cut corner for it. */
  --r-mark:  2px;
  --r-card:  6px;    /* anything with an edge AND content: a card, a field, a button */
  /* FULLY ROUND, AND TWO THINGS GET IT: a thing that is ONE OF SEVERAL CHOICES
     (a chip), and a thing whose shape IS a circle — a plate, a dot, a grab
     handle, a spinner. The first draft said "and nothing else", and the same
     sheet then used it four times for the second kind: a rule contradicted by
     the file it is written in is not a rule, it is a wish. */
  --r-pill:  999px;

  /* ── AND FOUR QUESTIONS THE THREE VALUES DO NOT ANSWER ON THEIR OWN ────
     Each of these was decided twice, differently, by two components before it was written
     down here — which is the census a scale exists to end.

     1 · A SURFACE LARGER THAN A CARD TAKES THE CARD'S CORNER. There is no fourth value: a
     sheet, a layer, a panel is a card that happens to be big, and inventing a corner for size
     alone would say something about the size rather than about the thing.

     2 · A SURFACE THAT MEETS AN EDGE SQUARES THE SIDE IT MEETS. A sheet resting on the bottom
     of the screen keeps its top two; a notice with a coloured stripe down one side keeps the
     two away from it; a full-width band keeps none. A corner is what says a thing ENDS, and a
     thing that runs into an edge does not end there.

     3 · A GROUND DRAWN BY A STATE TAKES THE SHAPE OF WHAT IT IS UNDER, and adds nothing of its
     own. A row lit on hover is a band the width of its list, so it has no corners; a control
     lit on hover keeps the corner it already had. FOCUS SETS NO RADIUS AT ALL — an outline
     follows whatever the element has, and a state that reshapes the thing it is reporting is
     drawing a second thing.

     4 · A PART INSIDE A CLIPPING PARENT ADDS NO CORNER. A card's head, its bands and its rows
     are cut by the card; giving them their own would draw a rounded box inside a rounded box,
     one pixel apart. */

  /* THE COLOURED EDGE. 3px appeared seven times — the stripe on a notice, the
     rule over a stage, the colour band on a training card, the deload hatching
     — always meaning the same thing: THIS EDGE SAYS WHAT KIND OF THING THIS IS.
     Seven copies of one decision is the census a scale exists to end. */
  --edge:    3px;

  /* THE CLEARING A MARK BURNS OUT OF A HATCH. Where a letter is set straight on deload
     stripes there is no ground between the two, so the mark is drawn with a halo of
     whatever the cell stands on: a tight ring laid twice, opaque right at the glyph's
     edge, and a wide one behind it carrying the clearing past the stripe's own width.
     The week strip and the plan's week grid draw the same halo at the same two radii —
     the same answer in the same shape, written twice. The hairline pass of the ring is
     1px and needs no name; these two do.

     NOT `--edge`, which happens to be 3px. An edge is a line with a position; this is a
     blur radius. One number under two roles is how a token stops meaning anything. */
  --halo:      3px;
  --halo-wide: 6px;

  /* ── the widths the layout changes at ────────────────────────────────
     Three were in the sheet — 560, 700, 800 — each written where it was
     needed, none of them named. They are not arbitrary: each is the width at
     which a particular two-column arrangement stops having room, so the scale
     is the ARRANGEMENTS rather than the devices. Media queries CANNOT READ CUSTOM
     PROPERTIES, so this stays a list rather than three tokens: a property
     nothing can read is not a token, it is a note with a colon in it — and
     this sheet has already thrown two of those out.
       560px   two things side by side become two lines
       700px   a half-and-half split becomes one column
       800px   the spec rail leaves the side of its specimens */
  --r-frame: 14px;   /* not the app's: the phone outline this reference draws around a specimen */
  /* AND THE REST OF THIS PAGE'S OWN FURNITURE IS NOT THE SYSTEM EITHER. The
     masthead's clamped name, the 360px phone frame, the 74px plate discs, the
     34×22 swatch: bare values ON PURPOSE, because they belong to the reference
     and copying them into a screen would be copying the wrong thing. What the
     APP is built from is a token. Two of the four layer tokens are in the same
     position — nothing here is a page or a sticky bar, so `--z-page` and
     `--z-sticky` are the scale stated in full rather than components waiting
     to be found. */
  --tap:       44px; /* anything a thumb aims at on its own */
  --tap-tight: 32px; /* a control sharing a row with others */
  /* HOW WIDE THE APP EVER GETS. Every row in the shell is fluid, which is what a phone
     wants and what a desktop turns into nonsense: at 1440 a day cell measured 197,7px
     and an exercise row 1408, with its count a thousand pixels from its name. This is
     where growing stops. The figure is the widest phone the app is opened on rather
     than a taste — the design's own arithmetic is stated at 360 and 320, and what
     happens between there and here is a measurement rather than a claim.
     NOT `--w-`, which the weight scale already owns end to end. */
  --frame:    430px;
  /* AND HOW A BAND HOLDS ITS CONTENT INSIDE THAT. The bands themselves — the date bar's
     ground, the tab bar's edge — reach the screen's edges wherever they are; what stops
     at `--frame` is what stands IN them. That is a padding rather than a width, so no
     band needs a wrapper element to be centred inside: on a phone it is the page's own
     margin, and past the cap it grows to take up the difference.
     `100%` is the BAND's width, resolved per element, which is what makes one token
     serve every band. */
  --hold: max(var(--pad-page), calc((100% - var(--frame)) / 2 + var(--pad-page)));
  /* ── motion ──────────────────────────────────────────────────────────
     THREE DURATIONS, EACH WITH A JOB, and nothing longer than a layer. The
     first draft had two, one of which (`--settle`) was used by nothing, and
     three easing curves of which one was a token: `linear` on the spinner and
     `ease-in-out` on the pulse were chosen at the rule, like the weights were.

     A phone in a gym is held for seconds at a time. Motion here is feedback,
     never decoration — nothing on the path of writing down a set may wait for
     an animation to finish. */
  --m-tap:   90ms;   /* under the finger — it has to feel like the surface itself */
  --m-state: 160ms;  /* a thing changing state: a colour, an edge, a mark */
  --m-layer: 240ms;  /* a layer arriving or leaving. Nothing is slower than this */
  --m-turn:  720ms;  /* one turn of the working mark — a loop, not a transition */
  --m-hold:  1s;     /* a colour held to be seen: a flash somebody between two sets notices */
  --m-read:  8s;     /* a notice that asks nothing, left up long enough to be read, then taken away */

  /* THREE CURVES, EACH WITH A JOB. */
  --ease-out:  cubic-bezier(.16,.84,.44,1);  /* arriving, responding — quick, then settling */
  --ease-in:   cubic-bezier(.6,0,.84,.4);    /* leaving */
  --ease-move: cubic-bezier(.4,0,.2,1);      /* changing in place */

  /* WHAT MAY BE ANIMATED, and it is a closed list:
       color · background-color · border-color · opacity · transform
     Never height, width, top or left. Those cost a layout on every frame and a
     phone shows it — and a list that grows while you watch is a list you cannot
     tap. Never text: a number that counts up is a number you cannot read.
     ONE FOLD IS THE EXCEPTION: the shell's news band folds its height away once, at
     the top of the app, after it has counted down (shell.css `.freshfold`) - one line
     leaving, never a list growing, and nothing under a finger while it runs. */
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --ground:#0F1418; --raised:#161D22; --sunken:#0A0E11;
    --line:#242D34; --line-strong:#3A4750;
    --ink:#E8EDF0; --ink-quiet:#A3AFB7; --ink-faint:#79868F;
    --accent:#5AC8D8; --accent-soft:#0C262D; --on-accent:#08131C; --focus:#5AC8D8;
    --accent-2:#E3C94F; --accent-2-soft:#2B2606; --done-soft:#0E2A22;
    --icon-invert:0;
    /* The ring rises with the theme: the same five tones measure L 0,694–0,836 here. */
    --tone-l:0.755; --tone-c:0.12;
    --plate-25:#E4586C; --plate-20:#3E93DA; --plate-15:#F0C63C; --plate-10:#3BB56B; --plate-5:#7C878E;
    --refused:#E4796A; --kept:#48BFA2; --pending:#E5945F; --together:#B49CF5; --together:#B49CF5;
    /* Dark already sits near the veil's own colour, so it is made of the
       sunken ground instead — the page goes further down, not grey. */
    /* The neighbour is picked against the ground it will be seen on: on dark it
       steps toward the cooler side, where the accent has room to brighten. */
    --accent-lit:    #6FD3E0;
    --edge-quiet:  linear-gradient(var(--sweep),
        var(--line-strong) 0%, var(--line) 48%, var(--line-strong) 100%);
    --edge-accent: linear-gradient(var(--sweep), var(--accent-lit), var(--accent));
    --edge-soft:   linear-gradient(var(--sweep),
        color-mix(in srgb, var(--accent) 45%, var(--line)) 0%, var(--line) 70%);
    --fill-accent: linear-gradient(var(--sweep), var(--accent), var(--accent-lit));
    --scrim: color-mix(in srgb, var(--sunken) 82%, transparent);
    color-scheme:dark;
  }
}
:root[data-theme="dark"]{
  --ground:#0F1418; --raised:#161D22; --sunken:#0A0E11;
  --line:#242D34; --line-strong:#3A4750;
  --ink:#E8EDF0; --ink-quiet:#A3AFB7; --ink-faint:#79868F;
  --accent:#5AC8D8; --accent-soft:#0C262D; --on-accent:#08131C; --focus:#5AC8D8;
    --accent-2:#E3C94F; --accent-2-soft:#2B2606; --done-soft:#0E2A22;
    --icon-invert:0;
    /* The ring rises with the theme: the same five tones measure L 0,694–0,836 here. */
    --tone-l:0.755; --tone-c:0.12;
  --plate-25:#E4586C; --plate-20:#3E93DA; --plate-15:#F0C63C; --plate-10:#3BB56B; --plate-5:#7C878E;
  --refused:#E4796A; --kept:#48BFA2; --pending:#E5945F;
  /* The neighbour is picked against the ground it will be seen on: on dark it
     steps toward the cooler side, where the accent has room to brighten. */
  --accent-lit:    #6FD3E0;
  --edge-quiet:  linear-gradient(var(--sweep),
      var(--line-strong) 0%, var(--line) 48%, var(--line-strong) 100%);
  --edge-accent: linear-gradient(var(--sweep), var(--accent-lit), var(--accent));
  --edge-soft:   linear-gradient(var(--sweep),
      color-mix(in srgb, var(--accent) 45%, var(--line)) 0%, var(--line) 70%);
  --fill-accent: linear-gradient(var(--sweep), var(--accent), var(--accent-lit));
  --scrim: color-mix(in srgb, var(--sunken) 82%, transparent);
  color-scheme:dark;
}

