/* ============================================================
   LOTT MUSIC STUDIO PORTAL — design tokens
   Single source of truth. Components read these and nothing else.

   Layers:
     1. Palette        — the theme's colors, verbatim from theme.json
     2. Status trio    — ok / warn / late, each with a pale ground
     3. Fixed families — hues that must survive a retheme
     4. Type           — two faces, one 12-step ramp
     5. Geometry       — radii, shadows, motion, layout
     6. Recipes        — the tint formula, stated once
   ============================================================ */

:root {
	/* --- 0. the two grounds --------------------------------
	   THE PORTAL HAS TWO PALETTES AND ONE TOKEN LIST.

	   The dark half was flat. The card and the page are both unchanged —
	   the studio kept both grounds — and the contrast came from everything
	   between them instead: stronger hairlines, a brighter edge, and the
	   two quieter inks lifted. Secondary text on a card 10.0 → 12.0, quiet
	   text 6.2 → 7.7, and the hairline round a card 1.28 → 1.60, which is
	   what now says where a card begins.

	   Every colour below is written once, as light-dark(paper, slate).
	   Which half applies is decided by `color-scheme` alone — and the
	   portal answers that question itself rather than asking the operating
	   system. The default is `light`, full stop; the dark half arrives only
	   when the reader has asked for it and the app is stamped
	   data-theme="dark" (see the rules under this block).

	   THE SYSTEM IS DELIBERATELY NOT CONSULTED (the studio's call). A
	   portal that follows the OS gives a family a dark portal they never
	   asked for because their phone turns dark at sunset, and gives the
	   studio a different-looking portal from the one they set up. The
	   choice is a choice, it is stored against the person, and it travels
	   with them to any device they sign in on — which following the system
	   could never do.

	   This is deliberately NOT two copies of the palette under two
	   selectors. Forty tokens duplicated is forty chances for the dark half
	   to drift a release behind the light one, and no test can see it
	   happen — the page still renders, just wrongly. Written as pairs, a
	   colour that changes changes in both themes or in neither.

	   The five values that CANNOT be written this way — light-dark() takes
	   colours and nothing else — are gathered in one small block below,
	   which is the only duplication in the file. */
	color-scheme: light;

	/* --- 1. palette (theme.json presets) ------------------- */
	--base:        light-dark(#FFFFFF, #1B1F26);   /* cards */
	--surface:     light-dark(#F7F5F2, #14171D);   /* the page */
	--surface-2:   light-dark(#F0EDE8, #272E38);   /* wells, tracks, muted chips */
	--ink:         light-dark(#16130F, #F4F7FB);
	--ink-2:       light-dark(#3A352E, #D6DCE6);
	--muted:       light-dark(#6B6459, #A8B2C0);  /* lifted until it clears AA on the bubble, its palest dark ground */
	--line:        light-dark(#E9E5DE, #39414D);
	/* THE BRAND DOES NOT CHANGE WITH THE READER'S LAMP.
	   Lifted for the dark ground the way every other hue is, the accent went
	   to #FF3D74 — which reads beautifully on a dark card and drops white on
	   it from 3.85 to 3.40. White on accent is a standing decision taken at
	   3.85; quietly shipping it at 3.40 in half the portal is not that
	   decision, it is an erosion of it. The paper accent needs no lift to
	   work here — it already sits at 4.29 against a card and 4.66 against the
	   page — so it stays one colour, and the Save button stays one object. */
	--accent:      #FF0C59;
	--accent-2:    #FF5C8A;   /* hover; one colour, for the reason above */
	--accent-soft: light-dark(#FFE3EC, #3A1C29);
	--accent-ink:  light-dark(#C2003F, #FF9DB8);   /* accent legible as text on --base */

	/* Text that sits on a FILLED ground — the ink, a stat hue, an avatar
	   tone, a chart bar. It is not "white"; it is "the opposite of whatever
	   is filled behind it", and the two stopped being the same colour the
	   moment there was a second theme.
	   
	   Seventy-two rules across the sheets said #fff here. Forty-seven sat on
	   --ink and went invisible the moment the ink went pale. The other
	   twenty-five sat on a hue, and those failed for the opposite reason and
	   in a way no grep could see: every hue is LIFTED for a dark ground —
	   it has to be, or a 6% wash of it would not read — and a lifted hue is
	   too pale to carry white. Measured across all sixteen, white fell to
	   between 1.56 and 3.50; this ink puts every one of them back over 5.
	   
	   The accent is deliberately NOT in that set. White on accent is a
	   standing brand decision, and it stays white in both themes so the
	   Save button is one object rather than two. */
	--on-fill:      light-dark(#FFFFFF, #14171D);

	/* The quote bubble inside a record card, and anything else that has to
	   read as the CLEAN surface with a tinted card behind it. On paper that
	   is just --base; in the dark --base is darker than the tinted card, so
	   the bubble would punch a hole rather than lift. Same relationship,
	   different value. */
	--bubble:      light-dark(#FFFFFF, #303740);

	/* --- 2. status trio ------------------------------------ */
	/* Late is weight-matched to ok/warn on purpose: the portal is calm,
	   and a true alarm red would shout across every page it appears on. */
	--ok:      light-dark(#1F7A5C, #4ECB9B);  --ok-bg:   light-dark(#E7F2ED, #143026);
	--warn:    light-dark(#8F6209, #E0AE55);  --warn-bg: light-dark(#FAEFD7, #332818);
	--late:    light-dark(#A8322F, #F0736E);  --late-bg: light-dark(#FBE7E5, #3A1E1D);

	/* --- 3. fixed families ---------------------------------
	   Deliberately NOT derived from --accent: four fixed hues themed by a
	   future accent change is the combination that stops matching the day
	   somebody re-themes. Each stat hue is three values to one recipe:
	   bg (the wash), fill (the hue at full voice), ink (AA on the wash). */
	--stat-rose-bg:   light-dark(#FFEBF1, #3A1C29); --stat-rose-fill:   light-dark(#E4145C, #F2568B); --stat-rose-ink:   light-dark(#A50B44, #FFA8C4);
	--stat-amber-bg:  light-dark(#FDF0DB, #332818); --stat-amber-fill:  light-dark(#D9860F, #E0A64A); --stat-amber-ink:  light-dark(#8A5207, #F0C889);
	--stat-indigo-bg: light-dark(#ECEDFB, #232744); --stat-indigo-fill: light-dark(#4E58CE, #7C86E8); --stat-indigo-ink: light-dark(#333B96, #B0B6F5);
	--stat-teal-bg:   light-dark(#E3F3F0, #123231); --stat-teal-fill:   light-dark(#10877A, #3FB9A6); --stat-teal-ink:   light-dark(#0A5A51, #7FD8C9);

	/* Lesson tones: small solid marks (chart bars, badges, keys). Chosen to
	   sit in the gaps left by the stat hues above — the two systems meet on
	   the dashboard within an inch of each other. */
	/* The celebration banner's gold. It sat as a literal in two places — the
	   stylesheet and the picker that offers it — while every sibling banner
	   named a tone. One name now, so the set is provably one set. */
	--tone-gold: light-dark(#E8B93B, #F0CB63);
	--tone-0: light-dark(#7B3FA0, #B084D8);  /* violet */
	--tone-1: light-dark(#1B7C9B, #5FC2DE);  /* cyan   */
	/* Moss is the one hue whose dark cut is not simply its light cut
	   lifted. Lifted the obvious way (#9CC461) it measured ΔE 6.4 from the
	   card ground while its five siblings averaged 4.7 — the achievement
	   card shouted and the other five whispered. The fault was lightness,
	   not saturation, so this drops L* and holds chroma: ΔE 5.3 at the same
	   55 chroma, so it stays a moss rather than becoming an olive. */
	--tone-2: light-dark(#55801F, #70AC50);  /* moss   */
	--tone-3: light-dark(#B8442C, #E8896C);  /* clay   */
	--tone-4: light-dark(#A13A82, #DE84BE);  /* orchid */
	--tone-5: light-dark(#4C6076, #93A8BF);  /* slate  */

	/* Avatar tones: recognition only — never status. First tone is the
	   accent itself; material categories reuse b/c/d so "the blue one"
	   means the same hue on a face and on a file chip. */
	--av-b: light-dark(#3F6F8F, #6C9DBE);  --av-c: light-dark(#7A5AA6, #9A7BC4);  --av-d: light-dark(#2F7D63, #4FA383);
	--av-e: light-dark(#B06534, #D89660);  --av-f: light-dark(#4A5B8C, #7986C4);

	/* The band's default gradient + accent, for anything rendered before a
	   studio saved its own. */
	/* The band is brand furniture too, and it is bright in both themes —
	   so its gradient and its gold stay put, and the white on them stays
	   white. */
	--pa-grad-a: #E8125C;  --pa-grad-b: #F5804A;  --pa-accent-default: #FFD66B;

	/* --- 4. type ------------------------------------------- */
	--sans:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	--display: "Permanent Marker", "Comic Sans MS", cursive;

	/* The ramp. Old sheet used ~40 sizes; these 12 cover them within half a
	   pixel. Components may keep a deliberate exception, stated inline. */
	--fs-nano:  .6rem;    /* datetile caption, tile labels        */
	--fs-micro: .66rem;   /* eyebrows, chart minutes              */
	--fs-2xs:   .72rem;   /* pills, hints, meta captions          */
	--fs-xs:    .78rem;   /* row meta, small controls             */
	--fs-sm:    .84rem;   /* secondary body, filters              */
	--fs-md:    .88rem;   /* default UI body                      */
	--fs-base:  .92rem;   /* prose in cards                       */
	--fs-lg:    1rem;     /* card headings                        */
	--fs-xl:    1.12rem;  /* dialog heads, bill piece titles      */
	--fs-2xl:   1.25rem;  /* band headline (phone)                */
	--fs-3xl:   1.55rem;  /* tile values, band lead figures       */
	--fs-4xl:   1.85rem;  /* the view title (display face)        */

	/* --- 5. geometry --------------------------------------- */
	--r-xs:   8px;    /* icon buttons, tiny chips     */
	--r-sm:  10px;    /* inputs, small tiles          */
	--r-md:  12px;    /* notices, date tiles, options */
	--r:     16px;    /* cards-within-cards, rows     */
	--r-lg:  24px;    /* cards, the sidebar, bands    */
	--r-pill: 999px;

	/* The ink every shadow is mixed from. The alphas differ on purpose — a
	   dock does not cast a card's shadow — so what is shared is the COLOUR,
	   not the shadow. Twelve copies of the same three numbers were spread
	   across the sheets; changing the ink meant finding all twelve. */
	--shadow-rgb: 22, 19, 15;
	--shadow-sm: 0 1px 2px rgba(var(--shadow-rgb),.05), 0 4px 14px rgba(var(--shadow-rgb),.05);
	--shadow:    0 2px 4px rgba(var(--shadow-rgb),.04), 0 12px 36px rgba(var(--shadow-rgb),.07);

	/* The edge: one border voice for the whole portal. A filled surface —
	   card, panel, dressed field — wears 1px at 14% of the muted ink; a
	   chip wears the same 14% of its OWN ink, so a green chip keeps a
	   whisper of green in its outline. Quiet enough to read as refinement,
	   present enough that a pale fill never melts into the page. */
	--edge:      color-mix(in srgb, var(--muted) 14%, transparent);
	--edge-self: color-mix(in srgb, currentColor 14%, transparent);

	--ease:     cubic-bezier(.22,1,.36,1);   /* arriving */
	--ease-out: cubic-bezier(.4,0,1,1);      /* leaving: hold, then go */
	--t: .3s;

	/* Layout: the shell. --top is the one offset the app hangs from; the
	   sticky sidebar reads the same value so the two can never drift. */
	--maxw: 1240px;
	--gutter: 28px;
	--top: 80px;
	--side-w: 252px;
	--shell-gap: 32px;

	/* --- 6. recipes ----------------------------------------
	   THE TINT: "carry hue X quietly" = bg color-mix(X 9%, base),
	   border color-mix(X 30%, transparent). Used by lesson badges, wall
	   cards, category chips, chart bars (20%/30% for marks). Stated here
	   so a new tinted thing is a decision already made. */

	/* THE KIND WASH: how much of a record's own hue its card carries, and
	   how much its chip does. Two numbers rather than one, because they
	   want opposite things — the ground should recede far enough that a
	   scroll of entries reads as one list, and the chip should stay legible
	   enough to name the kind. Chained together (the chip at a fixed
	   multiple of the wash) quieting the ground dimmed the labels with it. */
	--kh-wash: 8%;
	--kh-chip: 12%;
}

/* THE FIVE VALUES light-dark() CANNOT HOLD.
 *
 * It takes colours and returns a colour, so a percentage, a bare rgb
 * component list, and a whole shadow value are all out of its reach. These
 * are the only tokens in the file written twice, and there is now exactly
 * one selector for the second copy: the stamp. There used to be a
 * prefers-color-scheme block beside it for readers who had said nothing —
 * it went when the portal stopped asking the operating system anything.
 *
 * `:root` here is rewritten to the app container by inc/scope-css.php, along
 * with the qualifier hanging off it — see lmsx_scope_selector(). */
:root[data-theme="dark"] {
	/* The hairline is a percentage of --muted, and one percentage cannot
	   serve both grounds: 14% of a pale ink on paper is a line, and 14% of
	   it on a near-black card is a rumour. */
	--edge: color-mix(in srgb, var(--muted) 26%, transparent);
	--kh-wash: 6%;
	--kh-chip: 26%;
	--shadow-rgb: 0, 0, 0;
	--shadow-sm: 0 1px 2px rgba(var(--shadow-rgb),.4), 0 4px 14px rgba(var(--shadow-rgb),.3);
	--shadow:    0 2px 4px rgba(var(--shadow-rgb),.35), 0 12px 36px rgba(var(--shadow-rgb),.45);
}

/* The switch writes one of these onto the app. The light one is what the
   root already says and is kept for the reader of this file: both states
   are named in one place, and neither is an absence. */
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }

/* A button with no colour of its own is not black on iOS — Safari paints it
   the system blue, which is why the composer's choices and the practice
   stepper's + and − came out blue on a phone and nowhere else. Every button
   that wants a colour states one; the rest take the text's. */
button { color: inherit; }

/* Same for a link the portal has not dressed. Today the theme says this
   too, so nothing changes on this site — but the portal should not need a
   particular theme to avoid painting a breadcrumb in browser blue. Links
   that want a colour (.tfine a, .wcard a) still state one. */
a { color: inherit; }

/* iOS zooms the whole page in when a field it focuses is under 16px, and
   every field here is .86rem. Rather than shrink the reader's world on
   every tap, the fields grow to 16px where a finger is doing the tapping.
   Stated in px on purpose: the threshold is 16 CSS pixels, not 1rem, and a
   reader who has scaled their default font must not fall under it.

   The !important is deliberate: every field is styled by a component rule
   (.comp .fld textarea and friends) that outranks this selector, and this
   is a floor the platform imposes rather than a preference a component is
   entitled to outvote. Measured before adding it — three fields were still
   at 13.76px without it. */
@media (pointer: coarse) {
	:is(input, select, textarea):not([type="checkbox"], [type="radio"], [type="file"]) {
		font-size: 16px !important;
	}
}

/* Focus is one story everywhere: 2px of accent, 2px off the control. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

/* Except where tabindex="-1" says "scripts move focus here, people never
   tab to it". Every navigation moves focus to the panel's heading so a
   screen reader follows the page instead of starting over — and Safari
   answers programmatic focus with :focus-visible, so a ring appeared
   around the heading on every tap. Nothing carrying -1 is in the tab
   order, so no keyboard user loses a cue by this being quiet. */
[tabindex="-1"]:focus,
[tabindex="-1"]:focus-visible {
	outline: none;
}
