/* ==========================================================================
   Design System v2.1 — SEMANTIC ROLE TOKENS
   The only layer components are allowed to consume.
   --------------------------------------------------------------------------
   Source: Figma "📖 Guidelines" (node 945:8483) §1 Colour (semantic use),
   §2 Light & dark mode, §3 Section accent colours, plus tokens.css.

   WHY THIS FILE EXISTS
   The old portal had components reading raw palette values and page-level
   aliases directly, which is why it ended up with 8 names for "primary text",
   14 for "border", and 54 phantom variables. It also made dark mode
   impossible to express: there was nothing central to repoint.

   THE RULE: components consume ONLY the roles below. If a component needs a
   colour that has no role, add a role here — never reach into
   --colour-* from a component.

   HOW DARK MODE WORKS
   Guidelines §2 defines it as a straight swap of the two anchors:
       light → background Seafoam, body copy Flint
       dark  → background Flint,   body copy Seafoam
   So every role is defined once on :root (light) and repointed in ONE dark
   block. One hook only — [data-theme="dark"]. The legacy `.dark-mode` and
   `body.dark` selectors are NOT supported here: nothing in the portal ever
   set them (116 dead selectors — see Portal Utilities/redesign/AUDIT.md).

   HOVER / VARIANT STATES
   Guidelines §1: "Use the 50–900 scale weights for hover states, backgrounds,
   borders and subtle variations — don't manually lighten, darken, or adjust
   opacity." Every state below is therefore a different scale step, never a
   filter() or an rgba() of the base. Follow that when adding roles.
   ========================================================================== */

:root {
    /* ── Surfaces ────────────────────────────────────────────────────────
       Seafoam's scale runs white → deep teal, so it supplies the whole
       light-mode surface ramp from a single family. */
    --surface-page:     var(--colour-seafoam-200);
  /* Seafoam — the §2 anchor */
    --surface-raised:   var(--colour-seafoam-50);   /* cards/panels above page */
    --surface-sunken:   var(--colour-seafoam-300);  /* wells, inset areas      */
    --surface-hover:    var(--colour-seafoam-300);
    --surface-selected: var(--colour-harbour-50);

    /* Cards INSIDE a panel. Deliberately not --surface-raised or
       --surface-sunken: the screens use a NEUTRAL step here, not a Seafoam one
       (Pebble 100 in light, Flint 600 in dark — LeadTimes/Desktop/Light
       1300:3351 and /Dark 1300:3299 agree, as do the Resources frames). On a
       Seafoam page a neutral card reads as a distinct material rather than as
       the same surface at a different height, which is the intent. */
    --surface-card:     var(--colour-pebble-100);

    /* A cell RECESSED INTO a card — the little labelled boxes on a patient card
       (MyPatientsCard 861:2789, Pebble 200 on the Pebble 100 card). Its own role
       because neither existing step fits: --surface-raised is Seafoam 50, which in
       light is LIGHTER than the card and so reads as lifted rather than let-in, and
       --surface-sunken is a Seafoam well on a Seafoam page, not a neutral inset on a
       neutral card. Continues --surface-card's neutral family in both themes: one
       step darker than the card in light, one step darker in dark too, so the
       relationship holds rather than inverting. */
    --surface-inset:    var(--colour-pebble-200);

    /* A TILE LIFTED OFF A CARD — the product/range tiles in the catalogue grid.
       [frame] RegisterPatient/Desktop/Product/Light 1535:16788, where the tiles
       are White on the Pebble 100 container.

       Its own role because nothing existing carries this pair. --surface-inset
       goes the wrong way here (Pebble 200 is DARKER than the card, and these
       tiles are lighter); --surface-raised is Seafoam 50, a green-white that
       belongs on the Seafoam page rather than on a neutral card — and putting
       green back on this surface is exactly what was just taken off it.

       The direction is consistent across themes for once: lighter than the card
       in both. */
    --surface-card-raised: #fff;              /* the frame says White, literally */

    /* ── Text ───────────────────────────────────────────────────────────
       Flint is the §2 body-copy anchor.

       --text-muted departs from §1's literal "Flint 200 or Pebble 200", which
       is 1.9:1 (pebble-200) / 2.4:1 (flint-200) on a Seafoam page — both fail
       WCAG AA for text, and 12px captions are where it matters most. Read
       literally the rule only works on a dark ground, so it's applied as
       written in the dark block below and stepped down here. CONFIRMED by
       Justin 2026-08-11: the 50–900 scale exists precisely so legibility is
       fixed by stepping. So this is the spec working, not a deviation from it.

       Pebble 500 was the first landing (4.6:1 on a Seafoam page) and is one
       step too light. Muted text mostly sits on a --surface-card, not on the
       page, and Pebble 100 is DARKER than Seafoam 200 — so the same colour
       measures worse there:

           Pebble 500 on Seafoam 200 (page)   4.6:1  ✓
           Pebble 500 on Pebble 100  (card)   3.6:1  ✗   ← where it's actually used
           Pebble 500 on white       (field)  4.2:1  ✗   ← input placeholders
           Pebble 600 on Pebble 100           5.5:1  ✓
           Pebble 600 on Seafoam 200          5.9:1  ✓
           Pebble 600 on white                6.4:1  ✓

       So the role was Pebble 600: one value that passes on every light surface
       it lands on, rather than one that passes only on the page.

       NOW FLINT 200, AS THE SPEC WRITES IT — Daniel's call, 13-Oct: "match
       spec. it should be lighter for sure" (muted text "showing heavy on v2 in
       light mode"). The Resources frames draw it Flint 200 too. Measured, so
       the trade is on record (flag for Justin):

           Flint 200 on Seafoam 200 (page)    2.2:1  ✗
           Flint 200 on Pebble 100  (card)    2.0:1  ✗
           Flint 200 on white       (field)   2.3:1  ✗

       Going back is this one line: var(--colour-pebble-600). */
    --text-body:     var(--colour-flint-500);   /* Flint — the §2 anchor */
    --text-strong:   var(--colour-flint-700);   /* headings              */
    --text-muted:    var(--colour-flint-200);   /* see note above        */
    --text-subtle:   var(--colour-pebble-400);  /* least emphasis        */
    --text-link:     var(--colour-harbour-500);

    /* TEXT ON A COLOURED FILL — two roles, because one cannot work.
       Light copy is only legible on the DARK brand hues:

           Seafoam 50 on Harbour 500     5.1:1  ✓
           Seafoam 50 on Rockpool 500    4.5:1  ✓
           Seafoam 50 on Meadow 500      2.1:1  ✗
           Seafoam 50 on Marram 500      1.5:1  ✗
           Seafoam 50 on Golden Hour 500 2.3:1  ✗

       The light hues need dark copy instead, and Flint 700 clears every one of
       them comfortably (Meadow 6.1:1, Golden Hour 6.4:1, Marram 9.2:1).

       DANIEL'S CALL, 14-Aug: white, as the frames draw it. I had flipped this to
       Flint 700 (6.1:1) on the reasoning that §1 assigns the fill colour and never
       states the label colour, so darkening the text was the smaller deviation. He
       decided for spec fidelity — the Download and Search buttons read as white on
       green in every frame, and that is the look.

       SO THIS IS KNOWINGLY 2.1:1 AND IT IS THE ONE ROLE IN THE SYSTEM THAT FAILS
       AA. Recorded plainly rather than quietly. It is a real cost: 15px white on
       Meadow 500 is hard to read in bright light, which is a nurse on a ward.

       THE FIX THAT KEEPS THE LOOK is one line, whenever it's wanted — step the FILL
       to Meadow 700 and white passes at 4.6:1, still unmistakably a green button.
       That's --intent-success, not this role. Worth putting to Justin as "same
       button, one shade deeper" rather than as an accessibility argument. */
    --text-on-brand:  var(--colour-seafoam-50);  /* on harbour / rockpool fills */

    /* ── Amber, for an action that writes ────────────────────────────────
       New query, which of the buttons on an order is the only one that writes.

       ONE VALUE FOR BOTH THEMES, so it is defined here and NOT restated in the
       dark block — Daniel, 4-Sep: "400 light and dark mode, keep text white for
       both", then "lets try 500 for both". Most roles in this file swap; this
       one deliberately does not, and the absence of a dark override says so.

       --colour-golden-hour rather than --colour-golden-hour-500, which is the
       same hex: the base token is the one the palette calls "accent amber", and
       it is how the buttons either side of this reference theirs (--colour-
       sea-pink, --colour-meadow, --colour-harbour-light). A numbered step here
       would read as a deliberate departure from the accent when it is the accent.

       IT FAILS AA, ON HIS EXPLICIT CALL. Measured across the ramp against
       #FFFFFF: 200 1.51:1, 300 1.86:1, 400 2.04:1, 500 2.24:1, 600 3.01:1,
       700 4.93:1. So 700 is the ONLY shade white text passes on, which is why
       it was chosen first and why he rejected it: "did you use golden hour 700
       or something in dark mode its horrid ... trust me". He is right that 700
       is a brown, not an amber.

       This therefore ships 2.24:1 on a 15px Medium label against a 4.5:1
       threshold. RECORDED, NOT ARGUED — his call, and one for Justin to settle
       rather than for a stylesheet to quietly override. The two ways out if it
       is revisited: keep this fill and put flint/700 on it (6.35:1), or go to
       600 (3.01:1 with white — better, still short, still recognisably orange).

       Still a PAIR, because a fill and the text on it are one decision even
       when neither varies. */
    --surface-amber:  var(--colour-golden-hour);
    --text-on-amber:  var(--colour-seafoam-50);
    --text-on-accent: var(--colour-seafoam-50);  /* on meadow / marram /
                                                    golden-hour fills — 2.1:1 on
                                                    Meadow, see above            */

    /* FORM FIELD LABELS — 12px, and that size is the whole reason this exists.
       The frames draw both the section headings and the field labels in
       colour/harbour-light (RegisterANewPatient 1300:4901, 1300:4917). One colour,
       but two very different sizes, and only one of them survives it on a
       Pebble 100 card:

           24px Bold headline   Harbour Light 2.6:1 ✗ → Harbour 500  4.4:1 ✓
                                (large text needs 3:1, so 500 clears easily)
           12px Medium label    Harbour 500   4.4:1 ✗ → Harbour 600  6.2:1 ✓
                                (small text needs 4.5:1, and 500 misses by 0.1)

       So the headline can use --brand-primary, which already steps to Harbour 500,
       and the label needs one step further. Same shape as the intent roles: the
       lighter weight for something large, a darker one for something you read at
       12px. Missing it by 0.1 is exactly the kind of near-miss that never gets
       caught by eye. */
    --text-label: var(--colour-harbour-600);     /* 6.2:1 on a card */

    /* ── Borders ────────────────────────────────────────────────────────
       Three weights only. The old system had fourteen names for this. */
    --border-subtle: var(--colour-pebble-200);
    --border-medium: var(--colour-pebble-300);
    --border-strong: var(--colour-flint-300);
    --border-focus:  var(--colour-harbour-500);

    /* ── Brand ──────────────────────────────────────────────────────────
       Harbour is primary, Rockpool secondary, Meadow the brand green
       (Guidelines §1 role table). */
    --brand-primary:        var(--colour-harbour-500);
    --brand-primary-hover:  var(--colour-harbour-600);
    --brand-primary-subtle: var(--colour-harbour-50);
    --brand-secondary:      var(--colour-rockpool-500);
    --brand-accent:         var(--colour-meadow-500);

    /* Generic / neutral actions — §1 gives two options, "Harbour Light (blue)
       or Pebble (grey)". Both are roles so a component can pick by weight:
       an unremarkable-but-clickable action vs a genuinely recessive one. */
    --action-generic:       var(--colour-harbour-light);
    --action-generic-hover: var(--colour-harbour-500);
    --action-neutral:       var(--colour-pebble-500);
    --action-neutral-hover: var(--colour-pebble-600);

    /* ── Intent / status ────────────────────────────────────────────────
       Success and danger are quoted from §1 "Semantic use (working intent)":
       positive/success → Meadow, negative/error/destructive → Sea Pink.
       Warning → Golden Hour (agreed with Justin 2026-08-11; see below).

       EACH INTENT HAS THREE ROLES, and the split is not decorative:

         --intent-X          the 500. Fills, borders, icons, status dots.
                             Judged against WCAG 1.4.11 non-text contrast (3:1),
                             which these clear.
         --intent-X-subtle   the 50. Background tint behind the message.
         --intent-X-text     the 700. Text sitting on that subtle background.

       The 500 weights are NOT text colours on a light ground — Sea Pink 500 is
       3.4:1 and Golden Hour 500 is 2.0:1 against Seafoam. Every "our error text
       is unreadable" bug in the classic portal is this mistake. Use the 500 for
       the thing you see and the 700 for the thing you read.

       And never signal state by colour alone (WCAG 1.4.1) — an icon or a word
       always carries the meaning too. That is also what makes it a non-issue
       that Golden Hour is simultaneously the My Patients section accent: §3
       scopes accents to HEADINGS, warnings are filled blocks with an icon, so
       form separates them even though the hue is shared. */
    --intent-success:        var(--colour-meadow-500);
    --intent-success-subtle: var(--colour-meadow-50);
    --intent-success-text:   var(--colour-meadow-700);       /* 4.6:1 */

    --intent-warning:        var(--colour-golden-hour-500);
    --intent-warning-subtle: var(--colour-golden-hour-50);
    --intent-warning-text:   var(--colour-golden-hour-700);  /* 4.5:1 — the
                                tightest of the four; if a warning ever needs
                                to be small print, step to 800 (8.1:1) */

    --intent-danger:         var(--colour-sea-pink-500);
    --intent-danger-subtle:  var(--colour-sea-pink-50);
    --intent-danger-text:    var(--colour-sea-pink-700);     /* 7.1:1 */

    --intent-info:           var(--colour-harbour-400);
    --intent-info-subtle:    var(--colour-harbour-50);
    --intent-info-text:      var(--colour-harbour-500);      /* 4.7:1 — Harbour
                                500 is the one 500 that IS a safe text colour,
                                which is why --text-link can use it */

    /* ── Notification badges ─────────────────────────────────────────────
       A count in a filled circle. Two meanings, and Daniel set which is which
       (17-Aug): RED = something wants your action, BLUE = something is new to
       read. Order queries take the red, Latest Updates the blue.

       NOTE THIS INVERTS THE FRAME, deliberately. SecondaryButtons (808:4205)
       puts a near-white circle with a blue digit on Order queries and the red
       one on Latest Updates. Daniel's ruling is the semantic reading — a query
       is waiting on the nurse, an update is only news — so it wins.

       WHY NOT --intent-danger / --intent-info: both fail as a filled circle
       under a white digit. Sea Pink 500 gives 3.43:1 and Harbour 400 gives
       2.96:1, against 4.5:1 for a 17px digit. One step each fixes it, and Sea
       Pink 600 is also what the frame's badge actually RENDERS (#C04644,
       pixel-sampled) — the old components.css comment pinned that red to
       --gradient-last-light-from (#E85E58), a gradient stop, which is both 3.4:1
       and not the measured colour.

       NOT REDEFINED IN DARK, on purpose: a saturated badge is one of the §2
       "same in both modes" colours, and both values clear white in either
       theme. The white digit is set by the component, not tokenised — a badge
       digit is never anything else. */
    --badge-attention:       var(--colour-sea-pink-600);     /* 5.0:1 w/ white */
    --badge-info:            var(--colour-harbour-500);      /* 5.1:1 w/ white */

    /* ── Card label / meta text ──────────────────────────────────────────
       The patient card's cell labels and its DOB line. BOTH ARE THE SAME IN LIGHT
       AND DARK — the frames say so outright: MyPatientsCard 861:2790 (light) and
       915:5231 (dark) both give the labels colour/seafoam/700, and both give the
       DOB colour/seafoam/600. Not redefined below for that reason.

       These exist as roles rather than as raw primitives in the component only so
       the "same in both themes" fact lives in one place. They are NOT --text-label
       (Harbour): I substituted that and Daniel called it — "the blue is too dark
       compared to spec", in both modes. It was Harbour where the file says Seafoam.

       MEASURED, NOT STEPPED, per the standing rule that the frame decides:
         labels  seafoam 700 on Pebble 200   2.29:1   (light)
                 seafoam 700 on Flint 500    2.95:1   (dark)
         DOB     seafoam 600 on Pebble 100   1.82:1   (light)
                 seafoam 600 on Flint 600    4.55:1   (dark)
       Three of those four are under 4.5:1. Recorded here so the number is never
       lost, and left at the frame's value because that is Daniel's call to make,
       not mine. */
    --text-card-label:       var(--colour-seafoam-700);
    --text-card-meta:        var(--colour-seafoam-600);

    /* ── Section accents (Guidelines §3) ─────────────────────────────────
       The five primary "apps" in the homepage dock. §3 scopes these tightly:
       the accent applies to HEADINGS, and only while the user is inside that
       section. Anything that isn't one of the five — staff side, admin,
       settings — takes the default (--text-strong) with no accent at all. So
       these are consumed by a section wrapper, never by a shared component. */
    --accent-add-patient:   var(--colour-meadow-500);       /* green  */
    --accent-request-order: var(--colour-harbour-light);     /* blue   */
    --accent-my-patients:   var(--colour-golden-hour-500);   /* orange */
    --accent-my-orders:     var(--colour-marram-500);        /* yellow */
    /* The three reference sections (Resources, Lead times, Latest updates) as
       one accent, used by their panel titles AND the selected nav item, so the
       two match (Daniel, 1-Oct). Flint 500, 8.5:1 on the pale pill. */
    --accent-resources:     var(--colour-flint-500);
    /* My account is not one of the five, but Daniel asked for its title in
       sea pink (30-Sep). 400 in BOTH themes: 500 read "too dark" on the light
       panel (Daniel, 30-Sep). MEASURED 2.7:1 on Seafoam 200, under the 3:1 for
       large text, and shipped on his call, as the panel subtitle was. */
    --accent-account:       var(--colour-sea-pink-400);      /* sea pink */

    /* ── The section nav's selected item ─────────────────────────────────
       Shape and structure are MEASURED — LeftNavSelection's Selected variants
       (AddNewPatient 979:296, RequestPatientOrder 979:302): an opaque pill
       carrying the section's accent as both the label and the icon, with the
       label staying Roboto Medium. So the accent is the whole signal.

       THE PILL FOLLOWS THE THEME. It was first built as Flint in both modes,
       reasoning that the nav sits on the wallpaper rather than on the page, so
       §2's swap had nothing to swap — and the production frames back that up,
       using the same component instance in their Dark and Light variants.
       Daniel called it on the render (2026-08-11): a dark pill on a pale
       wallpaper in light mode reads as a bug, not as a decision. So the pill
       takes §2's swap like any other surface — Seafoam in light, Flint in dark —
       and the accents are re-derived against whichever ground they land on.

       THE ACCENT WEIGHTS ARE NOT THE §3 VALUES ABOVE, in either mode. Read
       literally they fail WCAG AA as 15px text almost everywhere:

           on Flint (dark pill)      on Seafoam (light pill)
           Harbour Light   3.1:1 ✗   Meadow 500      2.1:1 ✗
           Meadow 500      4.0:1 ✗   Harbour Light   2.5:1 ✗
           Golden Hour 500 4.1:1 ✗   Golden Hour 500 2.0:1 ✗
           Marram 500      5.9:1 ✓   Marram 500      1.6:1 ✗

       Each steps to the first weight on its own scale that clears 4.5:1 against
       its own ground: UP the scale on the dark pill, DOWN on the light one. Same
       mechanism and same ruling as --text-muted above.

       Light lands on the 700s, which is exactly where --intent-*-text lands for
       the same reason — with Marram needing 800, the same exception the warning
       note above already flags. */
    --nav-selected-surface:       var(--colour-seafoam-200);
    --nav-selected-add-patient:   var(--colour-meadow-700);      /* 4.6:1 */
    --nav-selected-request-order: var(--colour-harbour-500);     /* 4.7:1 */
    --nav-selected-my-patients:   var(--colour-golden-hour-700); /* 4.6:1 */
    --nav-selected-my-orders:     var(--colour-marram-600);      /* 2.2:1 —
                                     WELL BELOW AA for 15px text (4.5:1), and
                                     that is Daniel's call, 1-Oct: Marram 800
                                     (7.1:1) read "almost black" beside the
                                     Marram 500 title, and 700 (3.8:1) still too
                                     dark. Also carries Queries */
    --nav-selected-default:       var(--accent-resources);       /* 8.5:1 — the
                                     secondary group, matching its titles */
}

/* ── DARK MODE ───────────────────────────────────────────────────────────
   §2's swap, applied by repointing roles only. No component-level dark
   rules should ever be needed; if one is, a role is missing above.

   Note the surface ramp inverts direction: in light mode "raised" is
   LIGHTER than the page, in dark mode it must be lighter-than-dark, i.e. a
   step UP the flint scale rather than down. Getting that backwards is what
   makes dark themes look flat.

   ─────────────────────────────────────────────────────────────────────────
   MEASURED vs INFERRED. Daniel asked whether this is really the file's dark
   mode or just "not light mode" (2026-08-11). Fair question, and the honest
   answer is: the surfaces and copy are measured, some of the hues were not.
   Tagged per line below so it's never ambiguous again.

     [frame]    read off a dark frame — LeadTimes/Desktop/Dark 1300:3299,
                the Resources and Register-a-patient dark panels, or
                Scrollbar_Vertical_Dark 841:4849
     [contrast] deviates from the frame, with the measurement that forces it
     [§1]/[§2]  the written spec applied literally
     [inferred] still a judgement call — no dark frame exercises it yet

   The correction that came out of asking: this block used to lift EVERY brand
   and intent hue a step or two, on the reasoning that "the 500s are tuned for
   light backgrounds and go muddy against Flint". That was mine, not the file's,
   and the dark frames contradict it — Harbour Light, Meadow 500 and Rockpool 500
   all appear in them UNCHANGED from light. §2 says as much in words: "most
   colours stay the same across both modes." So the lifts that survive are only
   the ones a contrast measurement forces, and they say so. */
[data-theme="dark"] {
    --surface-page:     var(--colour-flint-500);   /* [frame] the dark panels are
                            colour/flint — the §2 anchor */
    --surface-raised:   var(--colour-flint-400);   /* [inferred] lifted off the
                            page. No dark frame uses a raised surface yet */
    --surface-sunken:   var(--colour-flint-600);   /* [frame] */
    --surface-hover:    var(--colour-flint-400);   /* [inferred] */
    --surface-selected: var(--colour-harbour-800); /* [inferred] */

    /* Note the direction flips: in light a card is a NEUTRAL step (Pebble 100
       is darker than the Seafoam page), in dark it's a step DOWN the Flint
       scale. Both from the frames, not derived. */
    --surface-card:     var(--colour-flint-600);
    /* [frame] RegisterPatient/Desktop/Product/Dark 1535:15626 — the tiles are
       colour/flint (#3a4a50, Flint 500) on the Flint 600 container, so LIGHTER
       than the card, the same direction as light's White on Pebble 100. It
       shares a value with --surface-inset here and does not in light, which is
       precisely why it needs to be its own role rather than borrowed. */
    --surface-card-raised: var(--colour-flint-500);

    --surface-inset:    var(--colour-flint-500);   /* [frame] MyPatientsCard dark
                            915:5231 — colour/flint, which is LIGHTER than the Flint
                            600 card. The direction INVERTS from light mode (Pebble
                            100 → 200 goes darker). I had inferred Flint 700 from
                            light's relationship and Daniel caught it by eye; the
                            frame was always the answer. */

    --text-body:     var(--colour-seafoam-200);  /* Seafoam — the §2 anchor */
    --text-strong:   var(--colour-seafoam-50);
    --text-muted:    var(--colour-pebble-200);   /* §1's "Pebble 200", as written —
                                     6.8:1 on the page, 4.7:1 on a card. Dark
                                     mode is where §1 reads literally and works */
    --text-subtle:   var(--colour-flint-200);    /* §1's "Flint 200"              */
    --text-link:     var(--colour-harbour-300);   /* lifted for contrast on dark */

    /* Unchanged from light: the fills these sit on are the same in both modes
       (§2 — "most colours stay the same across both modes"), so the copy that
       has to be legible against them is too. */
    --text-on-brand:  var(--colour-seafoam-50);

    --text-on-accent: var(--colour-seafoam-50);   /* white, per Daniel — see the
                                     light block. 2.1:1 on Meadow, knowingly */

    /* Steps UP rather than down, the ground now being a Flint 600 card. Harbour
       Light measures 3.9:1 there — fine for the 24px headline, short of 4.5:1 for a
       12px label — and the 300 gives 5.1:1. [contrast] */
    --text-label: var(--colour-harbour-300);

    --border-subtle: var(--colour-flint-400);
    --border-medium: var(--colour-flint-300);
    --border-strong: var(--colour-pebble-400);
    --border-focus:  var(--colour-harbour-300);

    /* Brand hues mostly DON'T move — see the note above. Only the two with a
       measured problem do. */
    --brand-primary:        var(--colour-harbour-400);  /* [frame] the dark
                              panels use colour/harbour-light for card titles,
                              which IS harbour-400. Light is the deviation here,
                              not dark: it steps to 500 because 400 measures
                              2.6:1 on a Pebble 100 card */
    --brand-primary-hover:  var(--colour-harbour-300);  /* [inferred] */
    --brand-primary-subtle: var(--colour-harbour-800);  /* [§2] tint inverts */
    --brand-secondary:      var(--colour-rockpool-300); /* [contrast] the file
                              draws the scrollbar thumb as Rockpool 500 in both
                              modes; that is 2.6:1 on the Flint 600 track, under
                              1.4.11's 3:1. The 300 measures 4.6:1 */
    --brand-accent:         var(--colour-meadow-500);   /* [frame] unchanged from
                              light — the dark Search button is colour/meadow */

    --action-generic:       var(--colour-harbour-400);  /* [§1] Harbour Light in
                              both modes, per the role table */
    --action-generic-hover: var(--colour-harbour-300);  /* [inferred] */
    --action-neutral:       var(--colour-pebble-400);   /* [inferred] */
    --action-neutral-hover: var(--colour-pebble-300);   /* [inferred] */

    /* Dark inverts the text/subtle pair: the tint becomes the 900 and the text
       becomes a 200, so the same three roles keep the same jobs. [§2]

       The 500 FILLS stay 500 unless they fail 1.4.11's 3:1 against the Flint 500
       page. Measured: Meadow 4.0:1 ✓, Golden Hour 4.1:1 ✓, Harbour 400 3.5:1 ✓,
       Sea Pink 2.7:1 ✗ — so danger is the one that has to move, and it moves the
       minimum distance (the 400 is 3.1:1). Success used to be lifted to the 400
       here for no measured reason, and the dark Search button proves the file
       keeps it at 500. */
    --intent-success:        var(--colour-meadow-500);       /* [frame] 4.0:1 */
    --intent-success-subtle: var(--colour-meadow-900);
    --intent-success-text:   var(--colour-meadow-200);

    --intent-warning:        var(--colour-golden-hour-500);  /* [inferred] 4.1:1 */
    --intent-warning-subtle: var(--colour-golden-hour-900);
    --intent-warning-text:   var(--colour-golden-hour-200);

    --intent-danger:         var(--colour-sea-pink-400);     /* [contrast] the
                               500 is 2.7:1 on the page, under 3:1 */
    --intent-danger-subtle:  var(--colour-sea-pink-900);
    --intent-danger-text:    var(--colour-sea-pink-200);

    --intent-info:           var(--colour-harbour-400);      /* [§1] Harbour
                               Light, as in light mode. 3.5:1 */
    --intent-info-subtle:    var(--colour-harbour-900);
    --intent-info-text:      var(--colour-harbour-200);

    --accent-add-patient:   var(--colour-meadow-400);
    --accent-request-order: var(--colour-harbour-400);
    --accent-my-patients:   var(--colour-golden-hour-400);
    --accent-my-orders:     var(--colour-marram-400);
    --accent-resources:     var(--colour-flint-100);   /* Daniel, 1-Oct: "in Dark
                               mode have them at 100" rather than white. 6.2:1
                               on the selected pill, 7.8:1 on the panel */
    --accent-account:       var(--colour-sea-pink-400);

    /* The selected nav pill, swapped per §2 like any other surface. The accents
       step UP their scales here because the ground is now dark — the mirror of
       the 700s/800 used in light mode. Ratios against --nav-selected-surface. */
    --nav-selected-surface:       var(--colour-flint-500);
    --nav-selected-add-patient:   var(--colour-meadow-400);      /* 4.7:1 */
    --nav-selected-request-order: var(--colour-harbour-200);     /* 5.4:1 —
                                     Harbour 300 reaches only 4.1:1, so this one
                                     steps twice, mirroring Marram in light */
    --nav-selected-my-patients:   var(--colour-golden-hour-400); /* 4.5:1 */
    --nav-selected-my-orders:     var(--colour-marram-400);      /* 6.5:1 */
    --nav-selected-default:       var(--accent-resources);       /* Flint 100,
                                     6.2:1, matching the three panels' titles */
}
