@import url("cairo.css");

/* ==========================================================================
   Gorcian — UI Kit

   This is the ITPF tent pegging kit: the same Cairo type, the same scale, the
   same components, the same spacing. Only the palette differs, and the change
   is confined to the token block below — nothing under it was restyled.

   HOW THE THREE COLOURS DIVIDE THE WORK

   Red is the colour everyone already reads as "something is wrong", so making
   it the interactive colour puts it in two jobs at once. The French state's own
   design system (systeme-de-design.gouv.fr) settles this, and it is worth
   following because it is the one design system built on this exact tricolour:

     BLUE is the interactive colour — every control, link, active tab, focus
     ring and primary button. Blue means "you can act on this".

     RED is identity and status only — the wordmark, a live dot, a first place,
     the host line on an event header. It never goes on a control and never
     signals a destructive action.

     ERROR has its own red (--stop), deeper than the flag red, and it never
     appears alone: an error is always a tinted block with a word in it.

   The DSFR's own values (Bleu France #000091, Rouge Marianne #E1000F) are
   legally reserved for French State sites, so this uses the flag's own #0055A4
   and #EF4135 with the same division of labour.

   Flag red carries only 3.8:1 against white, which is a second reason it holds
   no text. Where red must carry a label, --accent-deep does it at 6.2:1.

   Light-only by design: white working surfaces, low-glare page ground. Built
   with logical properties throughout, so a right-to-left language needs a dir
   attribute rather than a second stylesheet.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   THEME ONE — TOVAR.  Default.

   From the TOVAR brand guide v1.0, July 2026: Oxford Blue, Prussian Blue,
   Indigo Dye, Selective Yellow, Mustard. The guide's own contrast rule is
   "White on Oxford · Oxford on Yellow", which is why --on-brand-2 is dark here
   and white in the other theme.

   Only the colours are borrowed. No wordmark, no icon, no lockup: this
   platform is owned by no federation and should not appear to be owned by a
   company either.

   The guide's 40/30/15/10/5 ratio is for brand collateral. On a results table
   somebody reads all day the working surfaces stay light and the yellow is the
   accent — buttons, active rows, first place — not a third of the pixels.
   --------------------------------------------------------------------------- */
:root{
  /* structure — Indigo Dye */
  --brand:#012E5D;
  --brand-head:#012E5D;
  --brand-line:#011F40;          /* Prussian Blue */
  --brand-text:#012E5D;
  --brand-tint:rgba(1,46,93,.05);
  --brand-tint-2:rgba(1,46,93,.10);

  /* interactive — Selective Yellow. Buttons, links, focus, active states. */
  --brand-2:#FDB101;
  --brand-2-soft:rgba(253,177,1,.16);
  --brand-2-deep:#7A5300;        /* gold dark enough to be TEXT on white */
  --brand-2-hover:#E29E01;       /* deeper yellow that still carries dark text */
  --on-brand-2:#011B2F;          /* Oxford on Yellow, 10.2:1 */

  /* identity — Mustard. Never on a control. */
  --accent:#FFD358;
  --accent-soft:rgba(255,211,88,.18);
  --accent-deep:#A05E00;

  /* The logo's figure. Its own token rather than --brand-2, because the mark is
     identity and must not follow the control colour — in the tricolour the
     controls go France blue while the figure goes flag red. The G itself is
     currentColor, so it is ink on a light ground and white on a dark one
     without a second drawing existing to fall out of step. */
  --logo-mark:#FDB101;

  /* ink — Oxford Blue and the deck's own cool greys */
  --ink:#011B2F;
  --body:#3E4C57;
  --muted:#5B6B78;
  --meta:#AEBBC5;

  /* surfaces */
  --page:#F4F6F8;
  --card:#FFFFFF;
  --surface:#F4F6F8;
  --surface-hover:#E7ECF1;       /* one step down from --surface */
  --line:#E9EEF2;
  --line-strong:#C4D0DA;

  /* minor — in TOVAR the brand yellow IS the medal gold, which is a happy
     accident rather than a collision: a rank badge is not a control. */
  --medal-1:#FDB101;
  --medal-2:#AEBBC5;
  --medal-3:#B07A3F;

  /* minor — grades read as depth of blue, so progression is visible at a
     glance down a start list. */
  --grade-low:#DCE6EE;
  --grade-mid:#3E7CA6;
  --grade-high:#012E5D;

  /* minor — the public header */
  --hero:linear-gradient(150deg,#011B2F 0%,#011F40 62%,#011B2F 100%);
  --hero-glow:rgba(253,177,1,.30);

  /* semantic — the green is the deck's own. The amber is derived because the
     brand yellow is spoken for by the controls.

     The red is the deck's #D64A3A darkened to #B3392B: at its published value
     it carries 4.29:1 on white, which is under the minimum for text. In the
     brand deck it marks large "DON'T" headings, where that is fine; here it
     has to hold a sentence in an error block, so it is deepened within the
     same hue. The tint behind it keeps the original. */
  --ok:#1B6F59;      --ok-bg:rgba(30,123,99,.12);
  --warn:#8F5400;    --warn-bg:rgba(160,94,0,.13);
  --stop:#B3392B;    --stop-bg:rgba(214,74,58,.10);
  --info:#012E5D;    --info-bg:rgba(1,46,93,.10);

  /* chart series — four inks that must be told apart FROM EACH OTHER.

     These are their own tokens rather than borrowed semantic ones, because the
     two jobs have opposite requirements. A semantic colour only has to be
     legible on its surface: --brand-2 and --accent-deep can both be correct
     gold-family tokens and still be a bug side by side on a chart, which is
     exactly what happened — the gold line and the amber line read as one
     series in two shades. A series ink is judged against the other inks.

     So: cool, warm, green, crimson — four different hues, each ≥3:1 on --card
     and each separated from its neighbours. tests/contrast.php measures both
     conditions so no future palette edit can quietly collapse two of them. */
  --series-1:#012E5D;
  --series-2:#C77B00;
  --series-3:#1B6F59;
  --series-4:#A3123A;

  /* What is laid over the page behind an open menu. Dark enough to say the
     page is not the thing being used, light enough to see where you were. */
  --scrim:rgba(1,27,47,.38);
  /* behind the full-screen photograph and on the small controls laid over a photograph */
  --viewer-bg:rgba(1,27,47,.92);
  --viewer-ink:#FFFFFF;

  --radius-pill:30px;
  --radius-card:14px;
  --radius-field:5px;
  --radius-ctrl:4px;

  --shadow-sm:0 1px 2px rgba(11,46,99,.06);
  --shadow:0 1px 3px rgba(11,46,99,.07), 0 8px 24px rgba(11,46,99,.06);
  --t:all .12s cubic-bezier(.455,.03,.515,.955);

  --sidebar:246px;
  --topbar:64px;
}

/* ---------------------------------------------------------------------------
   THEME TWO — the tricolour.

   Navy, France blue and flag red. The division of labour follows the French
   state's own design system (systeme-de-design.gouv.fr), which is worth
   following because it is the one design system built on this exact flag:
   blue takes every control, red is identity only and never a destructive
   action, and errors get their own separate red. Their values (Bleu France
   #000091, Rouge Marianne #E1000F) are legally reserved for State sites, so
   this uses the flag's own with their rules.

   ONLY THE TOKENS DIFFER. Nothing below this block is theme-aware, which is
   what makes switching safe: no layout can shift, because no layout changed.
   --------------------------------------------------------------------------- */
:root[data-theme="tricolour"]{
  --brand:#0B2E63;
  --brand-head:#0B2E63;
  --brand-line:#063A7E;
  --brand-text:#0B2E63;
  --brand-tint:rgba(11,46,99,.05);
  --brand-tint-2:rgba(11,46,99,.10);

  --brand-2:#0055A4;
  --brand-2-soft:rgba(0,85,164,.10);
  --brand-2-deep:#063A7E;
  --brand-2-hover:#063A7E;
  --on-brand-2:#FFFFFF;          /* white on France blue, 7.4:1 */

  --accent:#EF4135;              /* flag red — identity only, 3.8:1, holds no text */
  --accent-soft:rgba(239,65,53,.12);
  --accent-deep:#C1121F;         /* where red must carry a label, 6.2:1 */

  /* Flag red for the figure. Red may never take a control in this palette, and
     a logo is the one thing that is purely identity — so navy G, red figure,
     white ground reads as the tricolour without inventing a fourth colour. */
  --logo-mark:#EF4135;

  --ink:#12161C;
  --body:#454B54;
  --muted:#5A626D;
  --meta:#98A0AC;

  --page:#F2F5F9;
  --card:#FFFFFF;
  --surface:#F7F9FC;
  --surface-hover:#E8EDF5;
  --line:#E2E8F0;
  --line-strong:#CBD3DF;

  /* Medals stay metals here. Flag red for first place would collide with red's
     identity job — the badge would read as the platform, not as "won". */
  --medal-1:#C9A227;
  --medal-2:#8C97A5;
  --medal-3:#C08A52;

  --grade-low:#DCE6F5;
  --grade-mid:#3E6FA8;
  --grade-high:#0B2E63;

  --hero:linear-gradient(150deg,#0F1D33 0%,#12161C 62%,#0D1526 100%);
  --hero-glow:rgba(0,85,164,.5);

  --ok:#18753C;      --ok-bg:rgba(24,117,60,.10);
  --warn:#B34000;    --warn-bg:rgba(179,64,0,.12);
  --stop:#CE0500;    --stop-bg:rgba(206,5,0,.08);
  --info:#0063CB;    --info-bg:rgba(0,99,203,.10);

  /* Here the flag gives the first three away: blue, red, then green for the
     fourth hue. Note what is NOT reused — --brand-2 is France blue #0055A4 and
     --brand is navy #0B2E63, so the old scheme drew series one and series two
     as two blues a shade apart. Same class of bug as the tovar gold pair, in a
     palette where it would have looked deliberate. */
  --series-1:#0055A4;
  --series-2:#C1121F;
  --series-3:#18753C;
  --series-4:#8F5400;

  --scrim:rgba(18,22,28,.38);
}

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;
  background:var(--page);
  color:var(--body);
  font-family:'Cairo',system-ui,-apple-system,'Segoe UI',Roboto,
    'Noto Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;
  font-size:15px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4{margin:0;color:var(--ink);text-wrap:balance}
p{margin:0}
a{color:var(--brand);text-decoration:none}
a:hover{color:var(--brand-line)}
button{font-family:inherit}
:focus-visible{outline:3px solid var(--brand-2);outline-offset:2px;border-radius:3px}
.tnum{font-variant-numeric:tabular-nums}

/* ---------- shell -------------------------------------------------------- */
.shell{display:flex;min-height:100vh}

.sidebar{
  width:var(--sidebar);flex:none;background:var(--ink);color:#fff;
  display:flex;flex-direction:column;position:sticky;inset-block-start:0;height:100vh;
}
.brand{
  display:flex;align-items:center;
  padding:18px 20px;border-block-end:1px solid rgba(255,255,255,.1);
}
/* No width here. The rule that used to sit at this line said width:158px and
   quietly overrode whatever height the code asked the logo for — logo_mark(30)
   rendered five times that size and nobody noticed, because the number in the
   PHP looked right. The image now carries its own width and height attributes
   and the stylesheet leaves them alone. */
.brand .logo{max-width:100%;height:auto;display:block}

.nav{padding:14px 12px;display:flex;flex-direction:column;gap:3px;overflow-y:auto;flex:1}
.nav .grp{
  font-size:10.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:rgba(255,255,255,.38);padding:14px 10px 6px;
}
html[lang="zh"] .nav .grp{letter-spacing:0;text-transform:none;font-size:12px}
.nav a{
  display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:8px;
  color:rgba(255,255,255,.78);font-size:14px;font-weight:500;transition:var(--t);
}
.nav a:hover{background:rgba(255,255,255,.07);color:#fff}
.nav a[aria-current="page"]{background:var(--brand);color:#fff;font-weight:700}
/* The nav icon is an inline SVG now, not a glyph. It takes its colour from the
   link — currentColor — so it goes white on the navy sidebar, dims with the
   link when the link dims, and follows a theme switch without a second file
   existing to fall out of step. */
.nav a .ic{width:18px;height:18px;flex:none;opacity:.85}
.nav a:hover .ic,.nav a[aria-current="page"] .ic{opacity:1}
.nav a.soon{opacity:.4;pointer-events:none}
.nav a.soon::after{
  content:attr(data-soon);margin-inline-start:auto;font-size:10px;font-weight:700;
  background:rgba(255,255,255,.13);padding:1px 7px;border-radius:20px;
}
.credit{
  padding:14px 18px;border-block-start:1px solid rgba(255,255,255,.1);
  font-size:11px;line-height:1.5;color:rgba(255,255,255,.45);
}

/* The workspace switcher — a <details> in the sidebar header. Every selector
   is under .nav so the contrast audit judges it against the dark sidebar, not
   a white card. The accent tick is a token (--brand-2); white and white-alpha
   literals are allowed on the dark ground. */
.nav .wsswitch{
  margin:2px 4px 10px;border-radius:9px;background:rgba(255,255,255,.06);
}
.nav .wsswitch>summary{
  list-style:none;display:flex;align-items:center;gap:10px;cursor:pointer;
  min-height:44px;box-sizing:border-box;
  padding:10px 12px;color:#fff;font-size:13.5px;font-weight:700;
}
.nav .wsswitch>summary::-webkit-details-marker{display:none}
.nav .wsswitch>summary .grow{flex:1}
.nav .wsswitch>summary .chev{width:14px;height:14px;flex:none;opacity:.55;transition:var(--t)}
.nav .wsswitch[open]>summary .chev{transform:rotate(180deg)}
.nav .wsswitch>summary:hover{background:rgba(255,255,255,.05);color:#fff}
.nav .wsmenu{
  padding:4px;display:flex;flex-direction:column;gap:1px;
  border-block-start:1px solid rgba(255,255,255,.09);
}
.nav .wsmenu a{
  display:flex;align-items:flex-start;gap:10px;padding:9px 9px;border-radius:7px;
  color:rgba(255,255,255,.74);font-size:12.5px;font-weight:600;
}
.nav .wsmenu a:hover{background:rgba(255,255,255,.08);color:#fff}
.nav .wsmenu a[aria-current="true"]{color:#fff;background:rgba(255,255,255,.05)}
.nav .wsmenu a .ic{width:16px;height:16px;flex:none;margin-block-start:1px;opacity:.85}
.nav .wsmenu a[aria-current="true"] .ic{opacity:1;color:var(--brand-2)}
.nav .wsmenu a .tx{flex:1;min-width:0}
.nav .wsmenu a small{
  display:block;font-weight:400;font-size:10.5px;line-height:1.35;
  color:rgba(255,255,255,.44);margin-block-start:1px;
}
html[lang="zh"] .nav .wsmenu a small{font-size:11px}

.main{flex:1;min-width:0;display:flex;flex-direction:column}

.topbar{
  height:var(--topbar);flex:none;background:var(--card);border-block-end:1px solid var(--line);
  display:flex;align-items:center;gap:16px;padding-inline:24px;
  position:sticky;inset-block-start:0;z-index:20;
}
.topbar .ttl{font-size:16px;font-weight:700;color:var(--ink)}
.topbar .sub{font-size:12.5px;color:var(--meta)}
.topbar .sp{margin-inline-start:auto}

.evpick{
  display:flex;align-items:center;gap:9px;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius-pill);padding:6px 8px 6px 14px;font-size:13px;color:var(--ink);
}
.evpick .lvl{
  font-size:10.5px;font-weight:700;padding:2px 9px;border-radius:20px;
  background:var(--brand-2);color:var(--on-brand-2);white-space:nowrap;
}

.langsw{display:flex;gap:3px;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-pill);padding:3px}
.langsw button{
  border:0;background:transparent;cursor:pointer;padding:5px 13px;border-radius:var(--radius-pill);
  font-size:12.5px;font-weight:700;color:var(--muted);transition:var(--t);
}
.langsw button:hover{color:var(--ink)}
.langsw button[aria-pressed="true"]{background:var(--brand);color:#fff}

.who{display:flex;align-items:center;gap:10px}
.who .av{
  width:34px;height:34px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--brand-tint-2);color:var(--brand);font-size:12.5px;font-weight:700;
}
.who .nm{font-size:13px;font-weight:600;color:var(--ink);line-height:1.2}
.who .rl{font-size:11.5px;color:var(--meta);line-height:1.2}

.content{padding:24px;display:flex;flex-direction:column;gap:20px;flex:1}

/* ---------- generic pieces ---------------------------------------------- */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);box-shadow:var(--shadow-sm)}
.card-h{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:16px 20px;border-block-end:1px solid var(--line);
}
.card-h h2{font-size:15.5px;font-weight:700}
.card-h .hint{font-size:12.5px;color:var(--meta)}
.card-h .sp{margin-inline-start:auto}
.card-b{padding:20px}
.card-b.flush{padding:0}

.rule{
  font-size:11.5px;color:var(--brand);background:var(--brand-tint-2);
  padding:2px 9px;border-radius:20px;font-weight:600;white-space:nowrap;
}

.btn{
  display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;
  font-size:14px;font-weight:500;padding:10px 22px;border-radius:var(--radius-pill);
  transition:var(--t);white-space:nowrap;
}
/* A bare .btn is the primary action; modifiers change it, never the reverse. */
/* The text colour on the interactive fill is a token because it differs by
   theme: white on France blue, Oxford Blue on Selective Yellow. This is the
   only rule below :root that the themes reach into.

   EVERY hover rule states its colour as well as its background, even where the
   colour does not change. A button is an <a>, and a:hover sets a colour at
   specificity (0,1,1) — higher than .btn at (0,1,0) — so a hover rule that
   changes only the background hands the text colour to the link rule. In the
   tricolour that made --brand-line and --brand-2-hover the same #063A7E and
   the label vanished into its own button. Stating both is what makes a state
   self-contained instead of a cascade puzzle; tests/contrast.php enforces it. */
.btn,.btn-accent{background:var(--brand-2);color:var(--on-brand-2)}
.btn:hover,.btn-accent:hover{background:var(--brand-2-hover);color:var(--on-brand-2)}
.btn-brand{background:var(--brand);color:#fff}
.btn-brand:hover{background:var(--brand-line);color:#fff}
.btn-ghost{background:var(--surface);color:var(--ink);border:1px solid var(--line-strong)}
.btn-ghost:hover{background:var(--surface-hover);color:var(--ink)}
.btn-sm{font-size:13px;padding:7px 16px}
.btn:disabled{opacity:.45;cursor:not-allowed}

.pill{display:inline-block;font-size:12px;font-weight:700;padding:3px 11px;border-radius:20px;white-space:nowrap}
.pill.ok{background:var(--ok-bg);color:var(--ok)}
.pill.warn{background:var(--warn-bg);color:var(--warn)}
.pill.stop{background:var(--stop-bg);color:var(--stop)}
.pill.info{background:var(--info-bg);color:var(--info)}
.pill.mute{background:rgba(78,78,78,.09);color:var(--muted)}
.pill.gold{background:var(--medal-1);color:var(--ink)}

/* judge badge chips — colour encodes the ITPF badge level (Art. 111.1) */
.badge{
  display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:700;
  padding:2px 10px;border-radius:20px;white-space:nowrap;
}
.badge::before{content:"";width:8px;height:8px;border-radius:50%;background:currentColor}
.badge.l1{background:var(--grade-high);color:#fff}
.badge.l2{background:var(--grade-mid);color:#fff}
.badge.l3{background:var(--grade-low);color:var(--grade-high)}
.badge.local{background:rgba(78,78,78,.09);color:var(--muted)}
.badge.elec{background:var(--info-bg);color:var(--info)}

/* ---------- stat strip --------------------------------------------------- */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:14px}
.stat{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);padding:16px 18px}
.stat .k{font-size:11.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--meta)}
html[lang="zh"] .stat .k{letter-spacing:0;text-transform:none;font-size:13px}
.stat .v{font-size:29px;font-weight:700;color:var(--ink);line-height:1.15;margin-block-start:4px}
.stat .n{font-size:12px;color:var(--meta)}
.stat .v small{font-size:14px;font-weight:600;color:var(--meta)}

/* ---------- event header ------------------------------------------------- */
.ev{
  background:linear-gradient(135deg,var(--ink) 0%,var(--ink) 58%,var(--ink) 100%);
  border-radius:var(--radius-card);padding:26px 28px;color:rgba(255,255,255,.76);
  position:relative;overflow:hidden;
}
.ev::after{
  content:"";position:absolute;inset-block-start:-60%;inset-inline-end:-8%;width:420px;height:420px;
  background:radial-gradient(circle,var(--hero-glow),transparent 66%);pointer-events:none;
}
.ev .row{display:flex;flex-wrap:wrap;gap:18px;align-items:flex-start;position:relative;z-index:1}
.ev h1{color:#fff;font-size:25px;font-weight:700;line-height:1.25}
.ev .host{font-size:13.5px;color:var(--accent);font-weight:600;margin-block-end:7px}
.ev .meta{display:flex;flex-wrap:wrap;gap:18px;margin-block-start:14px;font-size:13px}
.ev .meta div{display:flex;flex-direction:column}
.ev .meta .k{font-size:11px;color:rgba(255,255,255,.5)}
.ev .meta .v{color:#fff;font-weight:600}
.ev .side{margin-inline-start:auto;display:flex;flex-direction:column;gap:9px;align-items:flex-end}
html[dir="rtl"] .ev .side{align-items:flex-start}

/* day progress */
.days{display:flex;gap:8px;flex-wrap:wrap}
.day{
  display:flex;align-items:center;gap:8px;background:rgba(255,255,255,.07);
  border:1px solid rgba(255,255,255,.14);border-radius:var(--radius-pill);
  padding:6px 14px;font-size:12.5px;color:rgba(255,255,255,.8);
}
.day b{color:#fff;font-weight:600}
.day .dot{width:7px;height:7px;border-radius:50%;flex:none}
.day.done .dot{background:var(--ok)}
.day.live .dot{background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.day.todo .dot{background:rgba(255,255,255,.3)}

/* ---------- tables ------------------------------------------------------- */
.tbl-wrap{overflow-x:auto}
table.t{width:100%;border-collapse:collapse;font-size:14px;background:var(--card)}
table.t thead th{
  background:var(--brand-head);color:#fff;font-weight:700;font-size:13px;
  padding:12px 13px;text-align:start;white-space:nowrap;
  border-block-end:1px solid var(--brand-line);position:sticky;inset-block-start:0;
}
table.t thead th.num,table.t td.num{text-align:end;font-variant-numeric:tabular-nums}
table.t tbody td{padding:11px 13px;color:var(--brand-text);border-block-end:1px solid var(--line)}
table.t tbody tr:nth-child(odd) td{background:var(--brand-tint)}
table.t tbody tr:hover td{background:var(--brand-2-soft);color:var(--brand-text)}
table.t tbody tr.grp-total td{
  background:var(--brand-tint-2);font-weight:700;color:var(--brand-line);
  border-block-end:1px solid rgba(255,255,255,.14);
}
table.t tbody tr.grp-total:hover td{background:var(--brand-tint-2);color:var(--brand-line)}
table.t tfoot td{padding:11px 13px;font-weight:700;color:var(--brand-line);background:var(--brand-tint)}
table.t .sub{display:block;font-size:11.5px;color:var(--meta);font-weight:400}
.flag{
  display:inline-grid;place-items:center;width:22px;height:16px;border-radius:2px;flex:none;
  background:var(--brand-tint-2);color:var(--brand);font-size:8.5px;font-weight:700;
}
.athlete{display:flex;align-items:center;gap:9px;min-width:0}
.athlete .bib{
  width:24px;height:24px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--brand-tint-2);color:var(--brand-text);font-size:11.5px;font-weight:700;
}
.rank{
  display:inline-grid;place-items:center;min-width:26px;height:26px;padding-inline:6px;
  border-radius:20px;background:var(--brand-tint-2);color:var(--brand-text);
  font-size:13px;font-weight:700;font-variant-numeric:tabular-nums;
}
.rank.m1{background:var(--medal-1);color:var(--ink)}
.rank.m2{background:var(--medal-2);color:var(--ink)}
.rank.m3{background:var(--medal-3);color:var(--ink)}
.neg{color:var(--stop);font-weight:600}
.zero{color:var(--meta)}

/* ---------- score entry -------------------------------------------------- */
.scorebtns{display:flex;gap:5px;flex-wrap:wrap}
.sb{
  border:1px solid var(--line-strong);background:var(--card);cursor:pointer;
  border-radius:var(--radius-ctrl);padding:5px 11px;font-size:12.5px;font-weight:700;
  color:var(--muted);transition:var(--t);min-width:42px;
}
.sb:hover{border-color:var(--brand);color:var(--brand)}
.sb[aria-pressed="true"]{background:var(--brand);border-color:var(--brand);color:#fff}
.sb.miss[aria-pressed="true"]{background:var(--muted);border-color:var(--muted);color:#fff}
.tin{
  width:78px;font-family:inherit;font-size:13.5px;font-variant-numeric:tabular-nums;
  background:var(--surface);border:.8px solid var(--line-strong);border-radius:var(--radius-field);
  padding:6px 9px;color:var(--ink);text-align:end;
}
.tin:focus{outline:0;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-tint-2)}

.legend{display:flex;flex-wrap:wrap;gap:10px}
.legend .li{
  display:flex;align-items:center;gap:9px;background:var(--surface);border:1px solid var(--line);
  border-radius:10px;padding:10px 14px;font-size:13px;flex:1 1 150px;
}
.legend .li b{
  display:grid;place-items:center;width:30px;height:30px;border-radius:50%;flex:none;
  background:var(--brand);color:#fff;font-size:13px;font-weight:700;
}
.legend .li.z b{background:var(--meta)}
.legend .li span{color:var(--ink);font-weight:600;line-height:1.25}
.legend .li em{display:block;font-style:normal;font-size:11.5px;color:var(--meta);font-weight:400}

/* ---------- jury compliance --------------------------------------------- */
.jury{display:flex;flex-direction:column}
.jrow{
  display:grid;grid-template-columns:1.15fr 1.5fr auto auto;gap:14px;align-items:center;
  padding:12px 20px;border-block-end:1px solid var(--line);font-size:13.5px;
}
.jrow:last-child{border-block-end:0}
.jrow .role{font-weight:700;color:var(--ink)}
.jrow .role em{display:block;font-style:normal;font-size:11.5px;color:var(--meta);font-weight:400}
.jrow .person{color:var(--body)}
.jrow .person em{display:block;font-style:normal;font-size:11.5px;color:var(--meta)}
.jrow.bad{background:var(--stop-bg)}
.jrow.warnrow{background:var(--accent-soft)}

.note{
  display:flex;gap:11px;align-items:flex-start;padding:13px 16px;border-radius:10px;
  background:var(--info-bg);font-size:13px;color:var(--brand-line);line-height:1.55;
}
/* .note.ok was missing, and note('ok', …) is called from several pages — every
   one of them has been rendering a success message in the informational blue.
   Both colours are stated, as every rule here must. */
.note.ok{background:var(--ok-bg);color:var(--ok)}
.note.warn{background:var(--warn-bg);color:var(--warn)}
.note.stop{background:var(--stop-bg);color:var(--stop)}
/* Inline SVG now, sized rather than typeset. The 1px nudge lines its optical
   centre up with the first line of the sentence beside it — a box aligned to
   the text box sits slightly high. */
.note .ic{flex:none;width:18px;height:18px;margin-block-start:1px}
.note b{font-weight:700}

/* ---------- class cards -------------------------------------------------- */
.runs{display:flex;gap:6px;flex-wrap:wrap}
.run{
  display:inline-flex;align-items:center;gap:5px;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius-ctrl);padding:3px 9px;
  font-size:11.5px;font-weight:600;color:var(--muted);white-space:nowrap;
}
.run b{color:var(--brand-text)}

/* ---------- tabs --------------------------------------------------------- */
.tabs{display:flex;gap:6px;flex-wrap:wrap;padding:14px 20px;border-block-end:1px solid var(--line);background:var(--surface)}
.tab{
  border:1px solid var(--line);background:var(--card);cursor:pointer;border-radius:var(--radius-pill);
  padding:7px 16px;font-size:13px;font-weight:600;color:var(--muted);transition:var(--t);
}
.tab:hover{border-color:var(--brand);color:var(--brand)}
.tab[aria-selected="true"]{background:var(--brand);border-color:var(--brand);color:#fff}
.tab .d{font-size:11px;opacity:.75;margin-inline-start:5px}

/* ---------- result card (print document) -------------------------------- */
.docbar{
  display:flex;flex-wrap:wrap;gap:12px;align-items:center;
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);padding:14px 20px;
}
.docbar .sp{margin-inline-start:auto}

.sheet{
  background:#fff;border:1px solid var(--line-strong);border-radius:6px;
  width:100%;max-width:820px;margin-inline:auto;padding:44px 46px;color:#1a1a1a;
  box-shadow:var(--shadow);
}
.sheet .doc-h{
  display:flex;gap:20px;align-items:flex-start;padding-block-end:16px;
  border-block-end:2px solid var(--brand-head);
}
.sheet .doc-h .logo{width:92px;height:auto;flex:none;display:block}
.sheet .doc-h .t1{font-size:12px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--brand-head)}
html[lang="zh"] .sheet .doc-h .t1{letter-spacing:0;text-transform:none;font-size:13px}
.sheet .doc-h h1{font-size:21px;font-weight:700;color:#111;line-height:1.3;margin-block-start:3px}
.sheet .doc-h .t2{font-size:13px;color:#555;margin-block-start:3px}
.sheet .doc-h .idblk{margin-inline-start:auto;text-align:end;font-size:11.5px;color:#666;line-height:1.6}
html[dir="rtl"] .sheet .doc-h .idblk{text-align:start}
.sheet .doc-h .idblk b{display:block;color:#111;font-size:13px;font-family:ui-monospace,Menlo,monospace}

.docmeta{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px;margin-block:20px}
.docmeta div{border-inline-start:3px solid var(--brand-tint-2);padding-inline-start:11px}
.docmeta .k{font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#888}
html[lang="zh"] .docmeta .k{letter-spacing:0;text-transform:none;font-size:12px}
.docmeta .v{font-size:14px;font-weight:600;color:#111}

table.doc{width:100%;border-collapse:collapse;font-size:13px;margin-block-start:8px}
table.doc thead th{
  background:var(--brand-head);color:#fff;font-size:12px;font-weight:700;
  padding:9px 10px;text-align:start;border:.8px solid var(--brand-line);
}
table.doc tbody td{padding:8px 10px;border:.8px solid rgba(255,255,255,.18);color:var(--brand-line)}
table.doc tbody tr:nth-child(odd) td{background:var(--brand-tint)}
table.doc .num{text-align:end;font-variant-numeric:tabular-nums}
table.doc tbody td b{color:#111}

.sigblk{margin-block-start:30px;border-block-start:1px solid #ddd;padding-block-start:22px}
.sigblk h3{font-size:13px;font-weight:700;color:#111;margin-block-end:4px}
.sigblk .sub{font-size:11.5px;color:#777;margin-block-end:18px}
.sigs{display:grid;grid-template-columns:1fr 1fr;gap:26px 34px}
.sig{display:flex;flex-direction:column;gap:3px}
.sig .line{border-block-end:1px dotted #999;height:34px}
.sig .nm{font-size:12.5px;font-weight:700;color:#111}
.sig .rl{font-size:11px;color:#777}
.sig .bd{font-size:10.5px;color:var(--brand-2-deep);font-weight:700}

.chair{
  margin-block-start:26px;background:var(--brand-tint);border:1px solid rgba(255,255,255,.14);
  border-radius:8px;padding:18px 20px;display:flex;gap:22px;align-items:flex-end;flex-wrap:wrap;
}
.chair .who2{flex:1 1 220px}
.chair .who2 .k{font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--brand)}
html[lang="zh"] .chair .who2 .k{letter-spacing:0;text-transform:none;font-size:12px}
.chair .who2 .v{font-size:15px;font-weight:700;color:#111}
.chair .who2 .s{font-size:11.5px;color:#666}
.chair .line{flex:1 1 200px;border-block-end:1px dotted #888;height:40px}

.verify{display:flex;gap:16px;align-items:center;margin-block-start:24px;padding-block-start:18px;border-block-start:1px solid #eee}
.verify .qr{width:74px;height:74px;flex:none;border:1px solid #ddd;border-radius:4px;padding:5px;background:#fff}
.verify .tx{font-size:11.5px;color:#777;line-height:1.6}
.verify .tx b{display:block;color:#111;font-size:12.5px}
.verify .tx code{font-family:ui-monospace,Menlo,monospace;font-size:11px;color:var(--brand)}

/* scan-back proof panel */
.proof{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:16px}
.drop{
  border:1.5px dashed var(--line-strong);background:var(--surface);border-radius:10px;
  padding:22px;display:flex;gap:14px;align-items:center;
}
.drop .ic{
  width:42px;height:42px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--brand-tint-2);color:var(--brand);font-size:18px;
}
.drop .t{font-size:14px;font-weight:600;color:var(--ink)}
.drop .s{font-size:12px;color:var(--meta)}
.chain{display:flex;flex-direction:column;gap:0}
.step{display:flex;gap:12px;padding-block:10px;font-size:13px}
.step .mk{
  width:24px;height:24px;border-radius:50%;flex:none;display:grid;place-items:center;
  font-size:11.5px;font-weight:700;background:var(--ok-bg);color:var(--ok);
}
.step.todo .mk{background:rgba(78,78,78,.09);color:var(--muted)}
.step.live .mk{background:var(--warn-bg);color:var(--warn)}
.step .tx b{display:block;color:var(--ink);font-weight:600}
.step .tx em{font-style:normal;font-size:11.5px;color:var(--meta)}

/* ---------- footer credit ------------------------------------------------ */
.foot{
  margin-block-start:auto;padding:18px 24px;border-block-start:1px solid var(--line);
  display:flex;flex-wrap:wrap;gap:12px;align-items:center;font-size:12px;color:var(--meta);
}
.foot .sp{margin-inline-start:auto}
.foot b{color:var(--muted);font-weight:600}

/* ---------- responsive ---------------------------------------------------
   The sidebar used to be pushed to inset-inline-start:-260px below 1040px and
   brought back by a .open class that nothing ever set — the .burger rule was
   written, the element never was. Every page of the signed-in area was
   therefore unreachable on a phone, and on a tablet held upright.

   It is now display:none at that width instead of parked off the edge, and the
   disclosure menu in the topbar carries the same nav. Nothing is present but
   unreachable, and opening it needs no JavaScript.
   ------------------------------------------------------------------------- */
.navmenu{display:none}

@media (max-width:1040px){
  .sidebar{display:none}
  .navmenu{display:block;position:relative}
  .jrow{grid-template-columns:1fr;gap:6px}
  .sheet{padding:26px 22px}
  .sigs{grid-template-columns:1fr}
}
@media (max-width:820px){
  /* the topbar chips must never force the page wider than the viewport */
  .topbar{padding-inline:14px;gap:10px}
  .topbar > *{min-width:0}
  .topbar .ttl{font-size:14.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .topbar .sub,.who .rl,.who .nm,.evpick{display:none}
  .content{padding:14px}
  .ev{padding:20px}
  .ev h1{font-size:20px}
  .langsw button{padding:5px 10px;font-size:12px}
}

/* The menu button. 44px square is the floor Apple and Google both publish for
   a touch target, and it is the whole reason for the padding here — the glyph
   itself would be comfortable at half the size and unusable with a thumb. */
.burger{
  display:flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;
  border:1px solid var(--line);background:var(--card);color:var(--ink);
  border-radius:var(--radius-field);cursor:pointer;font-size:18px;
  list-style:none;user-select:none;
}
.burger::-webkit-details-marker{display:none}
.burger::marker{content:''}
.burger:hover{background:var(--surface-hover);color:var(--ink)}
.navmenu[open] > .burger{background:var(--brand);border-color:var(--brand);color:#fff}

/* The panel hangs under the button rather than sliding in from the edge: a
   drawer that covers the page needs a way out, and this one is dismissed by
   the same button that opened it, which is always visible. */
.menupanel{
  position:absolute;inset-block-start:calc(100% + 8px);inset-inline-start:0;
  z-index:60;width:min(84vw,290px);max-height:min(72vh,560px);overflow-y:auto;
  background:var(--ink);border-radius:var(--radius-card);box-shadow:var(--shadow);
  padding-block:6px;
  /* clear of the home indicator when this is wrapped for a store */
  padding-block-end:calc(6px + env(safe-area-inset-bottom));
}
.menupanel .nav{padding:8px 10px}

/* A scrim so a tap anywhere else closes the menu. It is drawn by CSS on the
   open state, not inserted by script, so it exists even when app.js does not
   load — and app.js only has to listen, never to build. */
.navmenu[open]::before{
  content:'';position:fixed;inset:0;z-index:50;background:var(--scrim);
}

/* ---------- a thumb is not a mouse pointer --------------------------------
   Apple publishes 44pt and Google 48dp as the smallest thing a finger can hit
   reliably. The controls here were laid out for a cursor: 21px nav links, 25px
   chips, 13px checkboxes. On a phone those are not small, they are a miss.

   Applied on a NARROW SCREEN OR A TOUCH DEVICE, not everywhere. Raising every
   desktop button to 44px would inflate a design that is correct as it is for
   the device it was drawn for; this is about the hand holding it, which is
   what (pointer:coarse) actually asks. The width clause is there because a
   phone in a browser reports the narrow viewport reliably, and emulated touch
   is not always reported at all.

   Padding, never font-size. A bigger target is a bigger box around the same
   words — growing the type instead would break the hierarchy and reflow the
   layout in the language that is already the longest.
   ------------------------------------------------------------------------- */
@media (max-width:1040px), (pointer:coarse){
  .btn,.btn-sm,.btn.sm,.tab,button.btn{min-height:44px;padding-block:11px}
  .btn-sm,.btn.sm{padding-inline:18px}

  /* Stable calendar: prev/today/next, Week/Month/Custom and the activity filter
     were 29–31px. The group grows; type size stays. */
  .calnav a,.calseg a{min-height:44px;box-sizing:border-box}
  .calnav a.i{min-width:44px;justify-content:center}
  .calbar .calfilter select,.calbar > select{height:44px;min-height:44px}

  /* Second line under a table's name column: 12px is the phone floor. */
  table.t .sub{font-size:12px}

  /* The nav, in the sidebar and in the drawer alike. */
  .nav a{min-height:44px;padding-block:12px}

  /* The public header's own links, which were 21px tall. Width matters as much
     as height here: "Kelas" is 30px of word, and a target has two dimensions. */
  .pub-bar nav a{display:inline-flex;align-items:center;justify-content:center;
    min-height:44px;min-width:44px;padding-inline:8px}
  .logo-link{min-height:44px;min-width:44px;justify-content:center}
  .pub-bar .pub-who{min-height:44px;justify-content:center}
  .pub-bar .pub-app{min-height:44px}

  /* Standalone links under a form — "Create an account", "View public results
     without signing in". They are not inside a sentence, so the inline
     exemption does not apply and should not: they are the next thing somebody
     taps after deciding not to sign in. */
  /* Scoped to .login-form at first, which meant forgot.php — the page somebody
     reaches precisely BECAUSE they cannot get in — had a 24px "back to signing
     in" link. The rule belongs to the shape, not to the one page that had it. */
  .after a,.login-form .hint a{
    display:inline-flex;align-items:center;min-height:44px}

  /* A file path alone in a table cell is the row's tap target, not a link in
     prose — so the WCAG 2.5.8 inline exemption does not cover it, and the audit
     was right to say so. The route map on app/docs.php has fifty of these; the
     rows get taller on a phone, which is the correct trade for being able to
     hit one. */
  .t.paths td a{display:flex;align-items:center;min-height:44px}

  /* The language picker: the button and each choice. */
  .langpick > summary{min-height:44px;display:inline-flex;align-items:center}
  .langpick a{min-height:44px;display:flex;align-items:center}

  /* The signed-in shell's one link out to the public site. A flex item is
     blockified regardless of the `a` it started as, so the inline-in-a-
     sentence exemption does not save this one either. */
  .foot a{display:inline-flex;align-items:center;min-height:44px}

  /* Filter chips. They stay pill-shaped and keep their type size; only the box
     around them grows. */
  .chip,a.chip{min-height:44px;min-width:44px;justify-content:center;padding-block:0}

  /* A tick box drawn at 13px cannot be hit. 24px is the floor WCAG 2.5.8 sets
     for a target, and the label beside it carries the rest — stretching the
     box itself to 44px tall would leave a 22×44 sliver, which is a worse
     shape to aim at than a square. */
  input[type="checkbox"],input[type="radio"]{
    width:24px;height:24px;min-height:0;flex:none}
  .sells label,.checkline,label:has(> input[type="checkbox"]),label:has(> input[type="radio"]){
    min-height:44px;display:flex;align-items:center;gap:10px}

  /* Download links on the brand page sat at 18px in a stacked caption. */
  .brandcell figcaption a{min-height:44px;display:flex;align-items:center}

  /* The sitemap in the public footer — a column of 30px links. */
  .sitemap a{min-height:44px;display:flex;align-items:center}

  /* The "see all" link a card header carries opposite its title. */
  .card-h > a{display:inline-flex;align-items:center;min-height:44px}

  /* The readout has to stay inside the card on a narrow screen. */
  .readout{max-width:min(70vw,240px)}
  .rangebar{gap:10px}
  .rangebar label{flex:1 1 100%}

  /* Form controls, so a date field is not a sliver. */
  input,select,textarea{min-height:44px}
  textarea{min-height:88px}
}

/* Type floors, from tools/mobile_audit.php.
   A label is glanced at and may be small; a RUN of text is read, and 12px is
   where that stops working on a phone. Below 10px nothing is legible at all,
   label or not — which is what the 8.5px country code was. */
.credit{font-size:12px}
.step .tx em{font-size:12px}
.flag{font-size:10px}

/* ---------- print -------------------------------------------------------- */
@media print{
  @page{size:A4;margin:14mm}
  body{background:#fff;font-size:11.5px}
  .sidebar,.topbar,.docbar,.foot,.noprint{display:none !important}
  .content{padding:0;gap:0}
  .shell{display:block}
  .sheet{
    max-width:none;width:100%;border:0;border-radius:0;box-shadow:none;padding:0;
  }
  table.doc thead th{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  table.doc tbody tr:nth-child(odd) td{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  .sheet .doc-h{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  .sheet .doc-h .logo{-webkit-print-color-adjust:exact;print-color-adjust:exact;width:80px}
  .chair{-webkit-print-color-adjust:exact;print-color-adjust:exact;break-inside:avoid}
  .sigblk{break-inside:avoid}
  tr{break-inside:avoid}
}
@media (prefers-reduced-motion:reduce){*{transition:none !important;animation:none !important}}

/* ---------- reveal-password toggle -------------------------------------- */
/* The button sits inside the field on the inline-end side, so it lands on the
   right in English and the left in Arabic without a second rule. */
.pw-wrap{position:relative;display:block}
.pw-wrap > input{width:100%;padding-inline-end:44px !important}
.pw-toggle{
  position:absolute;inset-block-start:50%;inset-inline-end:6px;transform:translateY(-50%);
  display:grid;place-items:center;width:32px;height:32px;padding:0;
  border:0;border-radius:6px;background:transparent;cursor:pointer;
  color:var(--muted);transition:var(--t);
}
.pw-toggle:hover{color:var(--brand);background:var(--brand-tint)}
.pw-toggle[aria-pressed="true"]{color:var(--brand)}
.pw-toggle:focus-visible{outline:3px solid var(--brand-2);outline-offset:1px}
.pw-toggle svg{display:block;pointer-events:none}

/* ==========================================================================
   Components added for Gorcian
   These belong in the kit, not in a page. A one-off style written inline is a
   style the next page cannot reuse and the stylesheet check cannot see.
   ========================================================================== */

/* The mark. Drawn by logo_mark() in inc/layout.php.

   The G is currentColor, but the mark sets its own: left to inherit it picked
   up whatever text colour it landed in, so inside a card it came out muted
   grey instead of brand ink. Two states only — ink, and white where it sits on
   a dark ground — and the shell says which by passing `on-dark`, rather than
   each context guessing. */
.logo{display:block;flex:none;color:var(--ink)}
.logo.on-dark{color:#fff}
.logo-link{display:inline-flex;align-items:center;flex:none}

/* The signed-in person, in the topbar. ITPF calls this .who; both names work
   so a page written against either reads correctly. */
.me,.who{min-width:0;text-align:end;line-height:1.25}
.me .nm{font-size:13px;font-weight:600;color:var(--ink);line-height:1.2;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.me .rl{font-size:11.5px;color:var(--meta);line-height:1.2}
@media (max-width:820px){.me,.who{display:none}}

/* A secondary line under a value — a class's variant, an official's grade.
   Not italic: synthesised oblique CJK is ugly, so this uses size and colour. */
.sub2{font-size:12px;color:var(--meta);font-style:normal;line-height:1.35}

/* Machine text: an email address, an imported rule line, a document id. */
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:12.5px;color:var(--muted);word-break:break-word}

/* ==========================================================================
   The marketplace
   A syllabus is a numbered list of modules, so it is laid out as one: the
   number carries real information — the order the coach means them to be
   taken in — which is the only reason to number anything.
   ========================================================================== */

.sechead{font-size:17px;font-weight:700;color:var(--ink);margin-block:30px 12px}

/* ==========================================================================
   Charts and metric tiles
   The chart arrives complete from inc/chart.php. app.js only animates it, so
   everything here has to look finished before a single line of script runs.
   ========================================================================== */

.metrics{display:grid;gap:12px;margin-block:14px;
  grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}
.metric{padding:16px 18px;background:var(--card);border:1px solid var(--line);
  border-radius:var(--radius-card)}
.metric .k{font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted)}
html[lang="zh"] .metric .k{letter-spacing:0;text-transform:none;font-size:13px}
.metric .v{font-size:26px;font-weight:700;color:var(--ink);line-height:1.2;
  margin-block-start:6px}
.metric .d{font-size:12px;font-weight:600;margin-block-start:4px}
/* Up is not automatically good — a faster time is a smaller number — so the
   arrow says direction and the reader decides. Colour stays neutral. */
.metric .d.up{color:var(--ok)}
.metric .d.down{color:var(--stop)}
.metric .d.flat{color:var(--meta)}

svg.chart{display:block;width:100%;height:auto;margin-block:14px 6px;overflow:visible}
svg.chart .grid{stroke:var(--line);stroke-width:1}
svg.chart .ax{fill:var(--meta);font-size:10.5px;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
svg.chart .ln{fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
svg.chart .pt{stroke:var(--card);stroke-width:1.2}
svg.chart{cursor:crosshair}

/* The crosshair the readout moves. Hidden until a pointer is on the chart, so
   a page without JavaScript is not left with furniture it cannot use. */
svg.chart .xhair{stroke:var(--line-strong);stroke-width:1;opacity:0}
svg.chart.live .xhair{opacity:1}

/* ---------- the notch and the home indicator ------------------------------
   viewport-fit=cover lets the page paint under both, which is what makes a
   wrapped app look native instead of letterboxed. The cost is that content
   under them is unreachable — a Sign out button behind the home indicator is
   a button nobody can press. These insets are zero in a browser window and
   only become real once this is installed or wrapped, so they cost nothing
   here and prevent the class of bug that only appears on a device.
   ------------------------------------------------------------------------- */
.topbar{
  padding-inline-start:max(24px,env(safe-area-inset-left));
  padding-inline-end:max(24px,env(safe-area-inset-right));
}
.content{
  padding-inline-start:max(24px,env(safe-area-inset-left));
  padding-inline-end:max(24px,env(safe-area-inset-right));
  padding-block-end:max(24px,env(safe-area-inset-bottom));
}
.foot{padding-block-end:max(14px,env(safe-area-inset-bottom))}
.sidebar{padding-block-end:env(safe-area-inset-bottom)}
@media (max-width:820px){
  .topbar{
    padding-inline-start:max(14px,env(safe-area-inset-left));
    padding-inline-end:max(14px,env(safe-area-inset-right));
  }
  .content{
    padding-inline-start:max(14px,env(safe-area-inset-left));
    padding-inline-end:max(14px,env(safe-area-inset-right));
  }
}

/* ---------- the chart on a phone -----------------------------------------
   These sit AFTER the rules above on purpose. The first attempt put them in
   the touch-target block higher up the file, where they lost to these on
   source order at equal specificity and did nothing at all — measured as a
   still-4px axis label while the stylesheet claimed to have fixed it.

   A 900-unit viewBox drawn 305px wide scales everything by 0.34, text with it.
   The axis labels are simply REMOVED rather than enlarged: at that scale the
   band left for them is about 10px tall, so a legible 11px label does not fit
   in the space the drawing gives it, and shrinking it to fit is how you get
   4px type that is texture rather than writing.

   Nothing is lost. Touch the chart and the readout names the date along with
   every figure — which is more than six squashed dates ever said.
   ------------------------------------------------------------------------- */
@media (max-width:1040px), (pointer:coarse){
  svg.chart .ax{display:none}
  /* A 2-unit stroke is a hairline once scaled, and a hairline outdoors in
     daylight is nothing. */
  svg.chart .ln{stroke-width:5}
  svg.chart .pt{r:6;stroke-width:3}
}

/* The figures. There is no y-axis on a chart carrying several metrics — one
   column of numbers would be true for one line and a lie for the others — so
   the real values live here and in the table below. */
.readout{
  position:absolute;z-index:3;pointer-events:none;
  min-width:8.5rem;padding:9px 11px;border-radius:10px;
  background:var(--card);border:1px solid var(--line-strong);
  box-shadow:var(--shadow);font-size:12.5px;color:var(--body);line-height:1.5;
}
.readout b{display:block;color:var(--ink);font-size:12px;margin-block-end:5px}
.readout .rl{display:flex;align-items:center;gap:7px;white-space:nowrap}
.readout .rl i{width:9px;height:9px;border-radius:2px;flex:none}
.readout .rl em{margin-inline-start:auto;font-style:normal;font-weight:700;color:var(--ink);
  font-variant-numeric:tabular-nums;padding-inline-start:12px}
.chart.empty{padding:28px;text-align:center;color:var(--muted);font-size:13.5px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-card)}

/* One chart per metric, stacked, sharing the x labels. Points, seconds and
   bonus points have no common scale; on one axis the smaller range flattens
   into a straight line and the trend it really has disappears. */
.chartrow{margin-block-end:6px}
.chartrow .ct{font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);margin-block-start:10px}
html[lang="zh"] .chartrow .ct{letter-spacing:0;text-transform:none;font-size:13px}

.legend{display:flex;flex-wrap:wrap;gap:14px;margin-block-end:14px}
.legend .li{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;color:var(--muted)}
.legend .li i{width:11px;height:11px;border-radius:3px;flex:none}

/* The window picker. A row of fields, not a card — it is chrome for the page
   below it rather than a thing in its own right. */
.rangebar{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;margin-block:16px 8px}
.rangebar label{display:flex;flex-direction:column;gap:5px;min-width:0}
.rangebar label > span{font-size:11.5px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
html[lang="zh"] .rangebar label > span{letter-spacing:0;text-transform:none;font-size:13px}
.rangebar input,.rangebar select{font-family:inherit;font-size:13.5px;padding:8px 11px;
  color:var(--ink);background:var(--card);border:1px solid var(--line-strong);
  border-radius:var(--radius-field)}
.rangebar input:focus,.rangebar select:focus{border-color:var(--brand-2);outline:0;
  box-shadow:0 0 0 3px var(--brand-2-soft)}

/* A live figure waiting on the server. Dimmed, not blanked: a number that
   vanishes while you type reads as an error. */
[data-live-out].stale{opacity:.45;transition:opacity .15s}
.subhead{font-size:13px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);margin-block:24px 8px}
html[lang="zh"] .subhead{letter-spacing:0;text-transform:none;font-size:14px}
/* A subhead may carry its own explanation rather than needing a paragraph under
   it. The span drops out of the uppercase micro-label and reads as prose, on the
   same line where there is room and under it where there is not. */
.subhead > span{display:inline;margin-inline-start:8px;font-size:12.5px;
  font-weight:400;letter-spacing:0;text-transform:none;color:var(--meta)}
html[lang="zh"] .subhead > span{font-size:13px}

/* Rule text, as the rule book set it.
   Pre-formatted because the indentation carries the sub-clause structure — a
   rule reflowed into a paragraph loses which bullet belongs under which. It
   scrolls inside its own box so the page never scrolls sideways. */
.rulebody{
  margin-block-start:12px;padding:16px 18px;max-height:30rem;overflow:auto;
  background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius-card);
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:12.5px;line-height:1.65;color:var(--body);
  white-space:pre-wrap;word-break:break-word;
}

/* A row in a syllabus: position, what it is, what it costs, what you can do. */
.modrow{
  display:flex;align-items:center;gap:14px;padding:14px 0;
  border-block-end:1px solid var(--line);
}
.modrow:last-of-type{border-block-end:0}
.modrow .n{
  flex:none;width:30px;height:30px;border-radius:50%;
  display:grid;place-items:center;font-size:13px;font-weight:700;
  background:var(--brand-tint-2);color:var(--brand-text);
}
.modrow .bd{flex:1;min-width:0}
.modrow .pr{flex:none;font-weight:700;color:var(--ink);white-space:nowrap}
.modrow .act{flex:none}

/* Lessons hang under their module, closed until asked for. */
.lessons{margin-block:0 8px;padding-inline-start:44px}
.lessons > summary{font-size:12.5px;color:var(--muted);cursor:pointer;padding-block:4px}
.lessons.open{padding-block-end:10px}
/* Top-aligned, not centred. A lesson body used to be a one-line blurb; the
   PO-13 course made them real reading, and a 22px tick centred against four
   paragraphs floats in the middle of nowhere. `.tick` gets a hair of offset so
   it lines up with the cap height of the title rather than its box. */
.lrow{display:flex;align-items:flex-start;gap:10px;padding-block:7px;font-size:13.5px;
  color:var(--body);border-block-end:1px solid var(--line)}
.lrow:last-child{border-block-end:0}
.lrow > .tick, .lrow > form > .tick, .lrow > .lspace{margin-block-start:1px}
.lrow > .pill{margin-block-start:2px}

/* A lesson people are meant to read, rather than a caption under a title.
   `.sub2` is 12px in --meta: right for "Duduk Dulu, Busur Kemudian · Ayu
   Prameswari", wrong for four paragraphs somebody has to know before they are
   allowed to compete. */
.ltext{font-size:13.5px;color:var(--body);line-height:1.65;margin-block-start:5px}
.ltext p{margin-block:0 9px}
.ltext p:last-child{margin-block-end:0}

/* Holds the tick's column on a row that has no tick, so a quiz sitting under a
   list of lessons lines up with them instead of shifting 32px left. */
.lspace{flex:none;width:22px}

/* Done, or not.
   --on-brand-2 is the colour for text ON the interactive fill, so it belongs
   only to the ticked state. Empty, the button is white and its mark would have
   been white too — invisible in the tricolour, where --on-brand-2 is white and
   the card is white. The audit measured 1.00:1 and was right to. */
.tick{
  flex:none;width:22px;height:22px;border-radius:50%;cursor:pointer;
  border:1.5px solid var(--line-strong);background:var(--card);color:var(--ink);
  font-size:12px;line-height:1;display:grid;place-items:center;padding:0;
}
.tick:hover{border-color:var(--brand-2);background:var(--card);color:var(--ink)}
.tick.on{background:var(--brand-2);border-color:var(--brand-2);color:var(--on-brand-2)}

/* A checkbox with a sentence beside it — a consent line, not a control chip.

   Its own class because `.tick` above is already a 22px round toggle, and
   borrowing that name put chip-sized type inside a chip-sized box and made the
   consent sentence unreadable. An existing class is a component, not a spare
   word; the same collision happened once before with `.flag`. */
.checkline{display:flex;align-items:flex-start;gap:10px;font-size:14px;
  line-height:1.55;color:var(--body);cursor:pointer}
.checkline input{flex:none;margin-block-start:3px}
/* `.form label > span` is the FIELD LABEL style — 11.5px, bold, uppercase —
   and it sets the size on the span itself, so inheriting from .checkline never
   reached it. A consent sentence is prose, not a field label, and 11.5px is
   under the floor for something somebody is being asked to read and agree to. */
.form .checkline > span{font-size:14px;font-weight:400;letter-spacing:0;
  text-transform:none;color:var(--body)}


/* A multi-select for a long list — thirty languages as tick boxes was a wall,
   and three was too few for a marketplace that is explicitly international.
   Sized so the scroll is obvious rather than a surprise. */
.langsel{min-height:auto;padding:6px;line-height:1.9}
.langsel option{padding:3px 6px;border-radius:4px}

/* ---------------------------------------------------------------------------
   The certificate template stage — app/template.php and app/certificate.php

   `container-type: size` is what makes the type scale with the ARTWORK rather
   than with the viewport. A field's size is stored as a percentage of the
   template's height and written as `cqh`, so one arrangement holds in the
   editor, on a phone, and on an A4 page. Sizing in px or vh would rearrange
   somebody's certificate every time the window changed.
   --------------------------------------------------------------------------- */
.tplstage{
  position:relative;width:100%;container-type:size;
  border:1px solid var(--line);border-radius:var(--radius-field);
  overflow:hidden;background:var(--surface);
}
.tplart{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  user-select:none;-webkit-user-drag:none}
.tplfld{
  position:absolute;line-height:1.15;white-space:nowrap;overflow:hidden;
  cursor:grab;border:1px dashed transparent;border-radius:2px;
}
/* The outline appears on hover rather than always. Somebody arranging a
   certificate needs to see it as it will print, and eight dashed boxes laid
   over the artwork is not that.

   BORDER ONLY, no background tint — and the contrast audit is what found the
   reason. Its law is that a state repainting the background must state its
   text colour, and here that colour cannot be stated: each field carries its
   own from the design, inline, which beats any rule written here. A CSS colour
   would be dead code that satisfied the linter and changed nothing. So the
   surface is left alone, which is also the honest answer — tinting the ground
   under a field misrepresents the certificate it is previewing. */
.tplfld:hover,.tplfld.dragging{border-color:var(--brand-2)}
.tplfld.dragging{cursor:grabbing;border-style:solid}

/* The same stage, but showing a real certificate rather than an arrangement.
   No hover outlines: this is the finished thing, not a thing being edited.

   Only `@page` stays inline in app/certificate.php, because @page applies to
   the whole document and this stylesheet already sets portrait with margins for
   the result card. Everything that is a CLASS belongs here — tests/smoke.php
   fails a class used in markup and never defined, and it was right to. */
.certsheet{border:0}
.certsheet .tplfld{cursor:default}
.certsheet .tplfld:hover{border-color:transparent}
@media print{
  /* Without this the artwork and the coloured text print as blank paper. */
  .certsheet,.certsheet img{
    -webkit-print-color-adjust:exact;print-color-adjust:exact;
  }
}

/* A grid of things to browse: courses, coaches. */
.cards{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}
.pcard{
  display:flex;flex-direction:column;gap:7px;padding:18px;text-decoration:none;
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);
  transition:var(--t);
}
.pcard:hover{border-color:var(--brand-2);box-shadow:var(--shadow);color:var(--ink)}
.pcard h3{font-size:15.5px;font-weight:700;color:var(--ink);line-height:1.35}
.pcard p{font-size:13px;color:var(--body);line-height:1.55;flex:1}
.pcard .foot{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  padding-block-start:8px;border-block-start:1px solid var(--line)}
.pcard .who2{font-size:12.5px;color:var(--muted)}
.pcard .pr{margin-inline-start:auto;font-size:12.5px;font-weight:700;color:var(--brand-text)}

/* ---------- who is teaching this, and why believe them -------------------- */

/* The standing row. Chips are facts, so they are quiet: no shouting, no ticks
   on things nobody checked. A `granted` chip is one somebody else awarded —
   a badge, an identity check — and it is the only kind that gets the brand
   colour, because it is the only kind the seller could not have written. */
.standing{display:flex;flex-wrap:wrap;gap:6px;margin-block:2px 4px}
.chip{
  display:inline-flex;align-items:center;gap:5px;padding:3px 9px;
  font-size:11.5px;font-weight:600;line-height:1.5;white-space:nowrap;
  border-radius:20px;border:1px solid var(--line-strong);
  background:var(--surface);color:var(--muted);text-decoration:none;
  flex:none;                    /* never squashed by the row it sits in */
}
.chip > *{flex:none}
.chip.granted{background:var(--brand-tint-2);border-color:transparent;color:var(--brand-text)}
/* The country box inside a granted chip needs the opposite ground, or it
   disappears into the tint the chip is already using. */
.chip.granted .flag{background:var(--card)}

/* Who a card belongs to, above the footer. */
.by{display:flex;flex-direction:column;gap:5px;padding-block-start:8px}

/* The provenance block: what was granted, by whom, when. */
.prov{margin-block-start:14px;padding:14px 16px;border-radius:var(--radius-card);
  background:var(--surface);border:1px solid var(--line)}
.prov h4{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);margin-block-end:7px}
html[lang="zh"] .prov h4{letter-spacing:0;text-transform:none;font-size:13px}
.prov p{font-size:13.5px;color:var(--body);line-height:1.6}
p.prov{margin-block-start:10px}

/* The filter bar. Ordinary links; the one in force is filled. */
.filters{display:flex;flex-direction:column;gap:10px;margin-block:16px 6px}
.fgrp{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.flab{font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);min-width:6.5rem}
html[lang="zh"] .flab{letter-spacing:0;text-transform:none;font-size:13px}
a.chip:hover{border-color:var(--brand-2);background:var(--surface);color:var(--ink)}
.chip.on{background:var(--brand-2);border-color:var(--brand-2);color:var(--on-brand-2)}
a.chip.on:hover{background:var(--brand-2-hover);border-color:var(--brand-2-hover);
  color:var(--on-brand-2)}

/* The seller's own checkbox list of what they offer. */
.sells{border:1px solid var(--line);border-radius:var(--radius-field);padding:12px 14px;
  display:flex;gap:16px;flex-wrap:wrap}
.sells legend{font-size:11.5px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);padding-inline:4px}
html[lang="zh"] .sells legend{letter-spacing:0;text-transform:none;font-size:13px}
/* A control that has been pressed and is waiting — the share card is fetched
   before the phone's share sheet can open, and on a slow connection that is a
   second of nothing happening. Opacity only: moving it would be a second thing
   to look at while waiting for the first. */
.busy{opacity:.55;pointer-events:none}

/* The explanations under a <select>, one of which applies. app.js hides the
   rest; with no script every one is shown, so this needs no reveal rule. */
.pickhelp{display:flex;flex-direction:column;gap:8px;margin-block-start:-6px}
.pickhelp > p{margin:0}

/* A tick and its words, on ONE line.
   `.form label` sets flex-direction:column — right for a field, where the label
   sits above its input — and at (0,2,0) it outranked plain `.chk` at (0,1,0).
   So inside a form every one of these stacked: the tick floated above its own
   words, centred, and the words picked up the 11.5px UPPERCASE field-label
   style. That is what the certification page looked like. `.form label.chk` is
   (0,3,0) and wins, and `.form .chk > span` puts the words back to prose.

   This is the fourth class collision in this project and the second caused by
   `.form label` specifically, which is why tests/smoke.php now measures
   specificity rather than trusting the next person to remember. */
.chk{display:flex;flex-direction:row;align-items:center;gap:7px;font-size:13.5px;
  color:var(--ink)}
.form label.chk{flex-direction:row;align-items:center;gap:7px}
.form .chk > span{font-size:13.5px;font-weight:400;letter-spacing:0;
  text-transform:none;color:var(--ink)}
/* A tick is not a field, so it does not take the field's full width.
   `.chk input{width:auto}` and `.form input{width:100%}` are BOTH (0,1,1), so
   the winner was decided by source order — and `.form input` is 23 lines further
   down, so it won. The checkbox stretched to 929px and pushed its own label 50
   pixels outside the card. Scoped to `.form .chk input` it is (0,2,1) and wins
   wherever either rule is moved to, which is the point: the last fix of this
   kind that relied on order is the reason this one existed. */
.chk input{width:auto;flex:none}
.form .chk input{width:auto;flex:none}
/* And the words take the room that is left, wrapping rather than overflowing. */
.form .chk > span{flex:1;min-width:0}

/* A row of buttons under a form. Wraps, because Bahasa labels are long and a
   button row that overflows is worse than one that takes two lines. */
.actions{display:flex;flex-wrap:wrap;gap:10px;margin-block-start:18px}

/* A destructive action, kept away from the ordinary ones. */
.danger{margin-block-start:22px;padding-block-start:16px;
  border-block-start:1px solid var(--line)}

/* Forms. No fixed widths anywhere: label text is 20-30% longer in Bahasa. */
.form{display:flex;flex-direction:column;gap:14px}
.form.row{flex-direction:row;flex-wrap:wrap;align-items:flex-end}
/* The flex sizing belongs to the ROW form only. On the default column form
   `flex:1 1 12rem` means grow along the column, so every field stretched to
   fill the card and the sign-in page came out as two inputs separated by a
   hand's width of nothing. A flex shorthand means different things on
   different axes; scope it to the axis it was written for. */
.form label{display:flex;flex-direction:column;gap:5px;min-width:0}
.form.row label{flex:1 1 12rem}
.form label > span{font-size:11.5px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
html[lang="zh"] .form label > span{letter-spacing:0;text-transform:none;font-size:13px}
.form input,.form select,.form textarea{
  font-family:inherit;font-size:14px;padding:9px 12px;color:var(--ink);
  background:var(--card);border:1px solid var(--line-strong);
  border-radius:var(--radius-field);min-width:0;width:100%;
}
.form input:focus,.form select:focus,.form textarea:focus{
  border-color:var(--brand-2);outline:0;box-shadow:0 0 0 3px var(--brand-2-soft)}

/* The calculator grid, and the line under each row that explains itself. */
.calc{margin-block-start:4px}
tr.why td{background:var(--surface);border-block-start:0;
  font-size:12px;color:var(--muted);padding-block:6px}

/* A narrow single-column card — register, and anything else asking for a
   handful of fields. */
.card.narrow{max-width:26rem;margin-inline:auto}

/* A style family heading, carrying the controls that act on the whole family.
   Hiding or renaming a family belongs on the page that lists the family, not
   on a second screen that does half the job. */
.fam{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-block:26px 10px}
.fam h4{font-size:15px}
.fam .sp{margin-inline-start:auto}
.fam form{display:flex;align-items:center;gap:6px;margin:0}
.fam-rename input{
  font-family:inherit;font-size:13px;padding:6px 10px;
  color:var(--ink);background:var(--card);
  border:1px solid var(--line-strong);border-radius:var(--radius-field);
  width:15rem;max-width:40vw;
}
.fam-rename input:focus{
  border-color:var(--brand-2);outline:0;box-shadow:0 0 0 3px var(--brand-2-soft)}

/* ==========================================================================
   Sign in
   The split screen from the ITPF kit: what the platform is on the left, the
   form on the right. Same proportions, same rhythm; the gradient and the glow
   are the --hero tokens the public header already uses, so this page changes
   with the palette instead of carrying its own copy of a colour.
   ========================================================================== */
.login-wrap{min-height:100vh;display:grid;grid-template-columns:1fr 1fr}
.login-side{
  background:var(--hero);color:rgba(255,255,255,.78);
  padding:56px 52px;display:flex;flex-direction:column;justify-content:center;
  gap:26px;position:relative;overflow:hidden;
}
.login-side::after{
  content:"";position:absolute;inset-block-start:-30%;inset-inline-end:-12%;
  width:460px;height:460px;pointer-events:none;
  background:radial-gradient(circle,var(--hero-glow),transparent 66%);
}
.login-side .in{position:relative;z-index:1;max-width:34em}
.login-side .logo{margin-block-end:30px}
.login-side h1{color:#fff;font-size:27px;font-weight:700;line-height:1.3}
.login-side p{margin-block-start:14px;font-size:15px;line-height:1.7}
.login-side ul{margin:22px 0 0;padding:0;list-style:none;
  display:flex;flex-direction:column;gap:11px}
.login-side li{font-size:13.5px;display:flex;gap:10px;align-items:flex-start}
.login-side li b{color:var(--accent);white-space:nowrap}

.login-form{display:flex;align-items:center;justify-content:center;
  padding:40px 28px;background:var(--card)}
.login-form .box{width:100%;max-width:380px}
.login-form h2{font-size:21px;font-weight:700;color:var(--ink);margin-block-end:6px}
.login-form .lede{font-size:14px;color:var(--muted);margin-block-end:26px}
.login-form .btn{width:100%;justify-content:center}
/* Two links now: "create an account" and "forgotten your password". Centred
   text ran them together into one sentence somebody had to parse. */
/* The links under a form: "create an account", "forgotten your password",
   "back to signing in". A row, so two of them read as two choices. */
.after{display:flex;flex-wrap:wrap;gap:6px 18px;margin-block-start:14px;
  font-size:13px}
.login-form .after{justify-content:center}

/* The ITPF login's own field rhythm, which is not the site's usual one: a
   sentence-case label in full ink rather than the uppercase micro-label the
   dense screens use, and a larger field on a tinted ground. A form somebody
   meets before they have an account should read as words, not as a data-entry
   grid. Scoped to this page so no other form changes. */
.login-form .form{gap:18px}
.login-form .form label{gap:7px}
.login-form .form label > span{
  font-size:14px;font-weight:600;color:var(--ink);
  letter-spacing:0;text-transform:none;
}
.login-form .form input{
  font-size:15px;padding:12px 14px;background:var(--surface);
  border-width:.8px;
}
html[lang="zh"] .login-form .form label > span{font-size:14px}

/* Whose account is whose, on a prototype that ships with one. */
.demo{margin-block-start:26px;padding:16px;background:var(--surface);
  border:1px solid var(--line);border-radius:10px;
  font-size:12.5px;color:var(--muted);line-height:1.75}
.demo b{color:var(--ink)}
/* The rule between the seeded administrator and the demo cast. A token border,
   not a colour literal — see the contrast audit. */
.demo hr{border:0;border-block-start:1px solid var(--line);margin-block:10px}
.demo code{font-family:ui-monospace,Menlo,monospace;font-size:12px;
  background:var(--card);border:1px solid var(--line);padding:1px 5px;
  border-radius:3px;color:var(--brand-text)}

/* One column below 900px, and the panel goes rather than shrinking to a
   stripe of gradient above the form. */
@media (max-width:900px){
  .login-wrap{grid-template-columns:1fr}
  .login-side{display:none}
}

/* A list of rule statements, read rather than scanned, so it keeps its bullet. */
ul.rules,ol.rules{margin:0;padding-inline-start:20px;display:flex;
  flex-direction:column;gap:5px}
ul.rules li,ol.rules li{font-size:13.5px;color:var(--body)}

/* A positive signed figure. Its opposite, .neg, is already in the kit. */
.pos{color:var(--ok)}

/* A supporting sentence under a form or a table. */
.hint{font-size:13px;color:var(--muted);margin-block-start:12px;max-width:62ch}

/* A stat tile whose value is a word rather than a number — an account type, a
   status. The numeric size is far too large for a phrase, and in Bahasa the
   phrase is longer again. */
.stat .v.sm{font-size:16px;line-height:1.3;font-variant-numeric:normal}

/* ---------- the language picker ------------------------------------------
   Shows only the language you are in and opens the rest, so it occupies one
   slot in the bar however many languages exist. A <details> element, so no
   script is involved and it works with scripting off.

   It appears on two different grounds — the white topbar and the dark public
   header — so the dark variant is stated rather than left to inherit.
   -------------------------------------------------------------------------- */
.langpick{position:relative;flex:none}
.langpick > summary{
  list-style:none;display:inline-flex;align-items:center;gap:7px;cursor:pointer;
  user-select:none;padding:6px 12px;border-radius:var(--radius-pill);
  border:1px solid var(--line-strong);background:var(--surface);
  font-size:12.5px;font-weight:700;color:var(--ink);transition:var(--t);
}
.langpick > summary::-webkit-details-marker{display:none}
.langpick > summary::marker{content:""}
.langpick > summary:hover{border-color:var(--brand-2)}
.langpick[open] > summary{background:var(--brand);color:#fff;border-color:var(--brand)}
/* The drawn flag — see flag_svg() in inc/icons.php for why it is drawn and not
   an emoji. A hairline border, because the white band of the Indonesian flag
   would otherwise dissolve into a light topbar and leave a floating red stripe.
   The border colour is a token, so it follows the theme. */
.langpick .flg{
  flex:none;display:block;border-radius:2px;
  border:1px solid var(--line-strong);}
/* On the dark public header the same hairline has to read against ink. */
.pub-bar .langpick > summary .flg{border-color:rgba(255,255,255,.35)}
/* The current language, as its code. Two or three characters now rather than
   "Bahasa Indonesia", which is what let this move to the end of the bar. */
.langpick .cur{white-space:nowrap;flex:none}
.langpick .caret{
  width:0;height:0;border-inline:4px solid transparent;
  border-block-start:5px solid currentColor;opacity:.7;
}
.langpick .menu{
  position:absolute;inset-block-start:calc(100% + 6px);inset-inline-end:0;z-index:60;
  background:var(--card);border:1px solid var(--line);border-radius:9px;padding:5px;
  box-shadow:var(--shadow);min-width:170px;
}
/* Open, each option gives the flag, the code AND the full name — this is where
   somebody is choosing rather than confirming, and a code alone is a guess. */
.langpick .menu a{
  display:flex;align-items:center;gap:9px;
  padding:8px 12px;border-radius:6px;font-size:13px;font-weight:600;
  color:var(--body);text-decoration:none;white-space:nowrap;
}
.langpick .menu .lcode{
  flex:none;min-width:2.4rem;font-size:11.5px;font-weight:700;
  letter-spacing:.04em;color:var(--meta);
}
.langpick .menu .lname{flex:1;min-width:0}
/* On the selected row the code sits on the brand fill, so it cannot keep the
   muted grey it has against the card. */
.langpick .menu a.on .lcode{color:#fff}
.langpick .menu a:hover{background:var(--surface);color:var(--ink);text-decoration:none}
.langpick .menu a.on{background:var(--brand);color:#fff}

/* On the dark public header the closed control has to read against ink. */
.pub-bar .langpick > summary{
  background:rgba(255,255,255,.10);border-color:rgba(255,255,255,.22);color:#fff;
}
.pub-bar .langpick > summary:hover{border-color:var(--accent)}
.pub-bar .langpick[open] > summary{background:#fff;color:var(--ink);border-color:#fff}

/* ---------- the theme picker --------------------------------------------- */
.themes{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}
.theme-opt{
  display:grid;gap:6px;padding:14px;border:1px solid var(--line-strong);
  border-radius:var(--radius-card);cursor:pointer;background:var(--card);transition:var(--t);
}
.theme-opt:hover{border-color:var(--brand-2)}
.theme-opt.on{border-color:var(--brand-2);box-shadow:0 0 0 3px var(--brand-2-soft)}
.theme-opt input{justify-self:start}
.theme-opt .swatches{display:flex;height:26px;border-radius:5px;overflow:hidden;
  border:1px solid var(--line)}
.theme-opt .swatches i{flex:1}
.theme-opt .theme-nm{font-size:14px;font-weight:700;color:var(--ink)}

/* ---- promo banner admin --------------------------------------------- */
.pb-list{display:flex;flex-direction:column;gap:14px;margin-block-end:20px}
.pb-row{display:flex;gap:16px;padding:14px;border:1px solid var(--line);
  border-radius:var(--radius-card);background:var(--card)}
.pb-thumb{flex:0 0 220px;display:block;border-radius:8px;overflow:hidden;
  border:1px solid var(--line);align-self:start}
.pb-thumb img{display:block;width:100%;aspect-ratio:4/1;object-fit:cover}
.pb-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:10px}
.pb-edit{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px}
.pb-edit label{display:grid;gap:4px;font-size:12.5px;color:var(--body)}
.pb-edit label:nth-child(4){grid-column:1/-1}
.pb-edit .actions{grid-column:1/-1;margin:0}
.pb-ctl{display:flex;flex-wrap:wrap;gap:8px;align-items:center;
  border-block-start:1px solid var(--line);padding-block-start:10px}
.pb-ctl form{display:inline}
.pb-add{border-block-start:1px solid var(--line-strong);padding-block-start:16px;
  display:grid;gap:10px;max-width:520px}
.pb-add h4{margin:0;font-size:14px;color:var(--ink)}
.pb-add label{display:grid;gap:4px;font-size:12.5px;color:var(--body)}
.pb-add label.pb-inline{grid-auto-flow:column;justify-content:start;align-items:center;gap:8px}
.pb-add .actions{margin:0}
@media (max-width:700px){
  .pb-row{flex-direction:column}
  .pb-thumb{flex-basis:auto}
  .pb-edit{grid-template-columns:1fr}
  .pb-edit label:nth-child(4){grid-column:auto}
}

/* ---- a progress bar ------------------------------------------------- */
.pgbar{height:12px;border-radius:6px;background:var(--surface);border:1px solid var(--line);
  overflow:hidden}
.pgbar-fill{height:100%;background:var(--brand);border-radius:6px 0 0 6px;
  transition:width .3s ease}
.pgbar-fill.done{background:var(--ok)}
.pgbar-sm{height:8px;min-width:90px}
.pgbar-cap{font-size:13px;color:var(--body);margin:8px 0 16px}
.pgbar-cap b{color:var(--ink);font-weight:700}

/* One colour, shown as itself. docs/uikit.php sets the fill inline because the
   value is parsed out of this file at run time — it is the one place where a
   literal colour in an attribute is the point rather than a mistake. The
   border keeps a swatch the same colour as the card from vanishing. */
.sw{display:inline-block;width:22px;height:22px;border-radius:var(--radius-ctrl);
  border:1px solid var(--line-strong);vertical-align:middle}

/* ==========================================================================
   The public site
   Taken from ITPF's public/_shell.php, where these lived inline. Moved into
   the kit so a page cannot quietly diverge from them and so the stylesheet
   check in tests/smoke.php can see them.
   ========================================================================== */

/* No overflow:hidden. The glow used to bleed past the header and be clipped,
   but clipping also swallows anything else that escapes the box — an open
   dropdown in the bar included. So the glow is kept inside its own bounds
   instead, which looks the same because it fades to transparent anyway, and
   the header can let a menu hang below it. */
.pub-head{
  background:var(--hero);
  color:rgba(255,255,255,.78);position:relative;
}
.pub-head::after{
  content:"";position:absolute;inset-block-start:0;inset-inline-end:0;
  width:min(420px,60%);height:100%;pointer-events:none;
  background:radial-gradient(circle at 70% 20%,var(--hero-glow),transparent 66%);
}
.pub-bar{display:flex;align-items:center;gap:18px;padding:16px 0;position:relative;z-index:2}
.pub-bar nav{display:flex;gap:20px;margin-inline-start:auto;align-items:center;flex-wrap:wrap}
.pub-bar nav a{color:rgba(255,255,255,.8);font-size:14px;font-weight:600;text-decoration:none}
.pub-bar nav a:hover,.pub-bar nav a.here{color:var(--accent)}
/* The signed-in indicator — a name and a state, not one more nav link, so a
   visitor who is already logged in can tell at a glance without following it.
   Sits after <nav> as its own flex item; nav's own margin-inline-start:auto
   already pulls everything from there to the end of the bar rightward. */
.pub-bar .pub-who{
  display:flex;flex-direction:column;align-items:flex-end;line-height:1.3;
  text-decoration:none;padding:1px 0;
}
.pub-bar .pub-who .nm{font-size:13px;font-weight:700;color:#fff}
.pub-bar .pub-who .rl{font-size:11px;font-weight:600;color:rgba(255,255,255,.62)}
.pub-bar .pub-who:hover .nm,.pub-bar .pub-who:hover .rl{color:var(--accent)}
/* The signed-in visitor's way back into the app — an actual button, not one
   more link the same weight as the nav row. */
.pub-bar .pub-app{
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--brand-2);color:var(--on-brand-2);
  font-size:13px;font-weight:700;text-decoration:none;white-space:nowrap;
  padding:9px 16px;border-radius:8px;
}
.pub-bar .pub-app:hover{background:var(--brand-2-hover);color:var(--on-brand-2)}
.pub-hero{padding-block:36px 52px;position:relative;z-index:1}
/* A page about ONE THING, not a page selling the platform. The class page spent
   205px of a dark band on a single word, because the hero is sized for a
   headline with a paragraph under it and a class with no variant gave it
   nothing to hold. Shorter, and the headline steps down with it. */
.pub-hero.tight{padding-block:22px 26px}
.pub-hero.tight h1{font-size:clamp(21px,2.6vw,28px)}
/* The identifying facts, as chips rather than a sentence: somebody arriving here
   is scanning for "which class is this", not reading. */
.pub-hero .herofacts{display:flex;flex-wrap:wrap;gap:6px 8px;margin-block-start:12px}
/* Scoped to .pub-hero, and not only for tidiness: the contrast audit works out
   which opaque surface a translucent fill sits on from the SELECTOR, and a bare
   `.herofacts span` told it nothing — so it composited white-on-white and
   reported 1.00:1. Naming the ground in the selector is how a rule stays
   checkable. */
.pub-hero .herofacts span{
  display:inline-flex;align-items:center;padding:3px 10px;border-radius:20px;
  font-size:11.5px;font-weight:600;line-height:1.6;white-space:nowrap;
  color:rgba(255,255,255,.80);background:rgba(255,255,255,.10);
  border:1px solid rgba(255,255,255,.18);}
.pub-hero h1{color:#fff;font-size:clamp(24px,3.6vw,36px);font-weight:700;line-height:1.25}
.pub-hero .sub{margin-block-start:10px;font-size:15px;color:rgba(255,255,255,.62);max-width:62ch}
.wrap{width:min(100% - 40px,1180px);margin-inline:auto}
.pub-main{padding-block:34px 60px}
.pub-foot{border-block-start:1px solid var(--line);padding-block:26px;margin-block-start:40px;
  font-size:12.5px;color:var(--meta);display:flex;flex-wrap:wrap;align-items:center;gap:12px}
.pub-foot .sp{margin-inline-start:auto}
/* A link in the footer bar is still a thing to tap: 44px tall, not the 20px of its line. */
.pub-foot a{display:inline-flex;align-items:center;min-height:44px}


/* A column of event cards. Gap rather than margins so an empty list collapses
   to nothing instead of leaving a hole. */
.evlist{display:flex;flex-direction:column;gap:12px}

.evcard{display:flex;gap:18px;align-items:center;padding:20px;border:1px solid var(--line);
  border-radius:var(--radius-card);background:var(--card);text-decoration:none;transition:var(--t)}
.evcard:hover{border-color:var(--brand-2);box-shadow:var(--shadow)}
.evcard .d{width:56px;height:56px;flex:none;border-radius:12px;background:var(--brand-tint-2);
  color:var(--brand);display:grid;place-items:center;font-size:20px}
.evcard .bd{flex:1;min-width:0}
.evcard .pr{flex:none;font-weight:700;color:var(--ink);white-space:nowrap}

/* A result that has not been signed off yet. Amber, not red: provisional is
   not an error, and red would say it is. */
.provisional{
  background:repeating-linear-gradient(135deg,var(--warn-bg) 0 12px,transparent 12px 24px);
}

.sitemap{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:26px;
  padding-block:34px 8px;margin-block-start:44px;border-block-start:1px solid var(--line);
}
.sitemap h4{
  font-size:11px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--meta);margin-block-end:11px;
}
html[lang="zh"] .sitemap h4{letter-spacing:0;text-transform:none;font-size:13px}
.sitemap a{display:block;font-size:13.5px;color:var(--muted);text-decoration:none;padding-block:4px}
/* --brand-2-deep, not --brand-2: the sitemap sits on the light page, and the
   interactive token is a FILL colour. Selective Yellow as text on #F4F6F8 is
   1.72:1 — the link disappeared on hover in the TOVAR theme exactly as the
   button label did. --brand-2-deep exists for gold that has to be text. */
.sitemap a:hover{color:var(--brand-2-deep)}

@media (max-width:760px){
  .pub-bar{flex-wrap:wrap;gap:10px}
  .pub-bar nav{margin-inline-start:0;flex-wrap:wrap;gap:12px}
  .pub-bar nav a{font-size:13px}
}

/* ---------------------------------------------------------------------------
   Brand assets — docs/brand.php

   A logo variant is invisibly wrong until it is on the ground it will be used
   on: a white mark looks perfect until somebody drops it on a white page. So
   every asset is staged on a real surface rather than a neutral swatch — the
   light ones on the page colour, the reversed and monochrome-white ones on
   ink, and the icons on a chequer, because their whole point is that the
   corners are transparent.
   --------------------------------------------------------------------------- */
.brandgrid{display:grid;gap:16px;margin-block-start:14px;
  grid-template-columns:repeat(auto-fill,minmax(230px,1fr))}
.brandcell{margin:0;border:1px solid var(--line);border-radius:var(--radius-card);
  overflow:hidden;background:var(--card)}
.brandstage{display:flex;align-items:center;justify-content:center;
  min-height:132px;padding:20px}
.brandstage img{max-width:100%;height:auto}
.brandstage.light{background:var(--surface)}
.brandstage.dark{background:var(--ink)}
/* Two tokens, not two literals — the chequer has to follow the theme like
   everything else, and tests/contrast.php fails on a colour that cannot. */
.brandstage.checks{
  background-color:var(--surface);
  background-image:
    linear-gradient(45deg,var(--line) 25%,transparent 25%,transparent 75%,var(--line) 75%),
    linear-gradient(45deg,var(--line) 25%,transparent 25%,transparent 75%,var(--line) 75%);
  background-size:18px 18px;
  background-position:0 0,9px 9px;
}
.brandcell figcaption{display:flex;flex-direction:column;gap:3px;
  padding:12px 14px 14px;border-block-start:1px solid var(--line)}
.brandcell figcaption b{font-size:13.5px;color:var(--ink)}
.brandcell figcaption .hint{font-size:12px;line-height:1.5}
.brandcell figcaption .pill{align-self:flex-start;margin-block:2px}
.brandcell figcaption a{font-size:11.5px;color:var(--brand);word-break:break-all;
  margin-block-start:4px}
.brandcell figcaption a:hover{color:var(--brand-line)}
.brandcell figcaption .meta{font-size:11px;color:var(--muted)}

/* docs/uikit.php has always marked its current tab with .here and nothing
   styled it, so the palette being shown looked the same as the one that was
   not. The background is stated with its text colour, as every state here
   must be. */
.tab.here{background:var(--brand);border-color:var(--brand);color:#fff}
.tab.here:hover{background:var(--brand-line);border-color:var(--brand-line);color:#fff}

/* ==========================================================================
   Stable calendar — week grid, month grid, and the bar that switches them.

   Every view is a URL (inc/stable_calendar.php). The bar's links reuse .chip /
   .chip.on. A slot is coloured by activity through an inline
   --cal-ink:var(--series-N), so no colour literal lives here.

   The grids are hidden below 820px and the day-grouped .card list that follows
   them takes over, so the calendar never scrolls sideways on a phone.
   ========================================================================== */

.calbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-block:16px 12px}
.calbar .sp{margin-inline-start:auto}
.calbar h3{font-size:15px;font-weight:700;color:var(--ink);margin:0}
/* the activity filter — one plain select, no submit button, sized to match the
   segmented controls EXACTLY. A .calnav / .calseg segment is: 12.5px/1 text +
   8px+8px padding + the group's 1px+1px border = 30.5px. The select is pinned
   to the same box height with an explicit `height`, and `min-height:0` undoes
   the 44px touch-target rule (@media at the "Form controls" block) which was
   hitting the select but not the <a> segments — that mismatch is the bug.
   It submits on change; the <noscript> button is the fallback. */
.calfilter{display:inline-flex;align-items:center;gap:6px}
.calbar select{
  box-sizing:border-box;height:30.5px;min-height:0;
  font:600 12.5px/1 system-ui;color:var(--body);
  padding:0 28px 0 11px;
  border:1px solid var(--line-strong);border-radius:7px;background:var(--card)
}
.calbar select:hover{color:var(--ink)}
.calbar select:focus{border-color:var(--brand-2);outline:0;box-shadow:0 0 0 3px var(--brand-2-soft)}

/* prev/today/next and Week/Month/Custom — each one bordered group with hairline
   dividers, the Google-Calendar segmented control. ~30px tall, small radius. */
.calnav,.calseg{
  display:inline-flex;background:var(--card);
  border:1px solid var(--line-strong);border-radius:7px;overflow:hidden
}
.calnav a,.calseg a{
  font:600 12.5px/1 system-ui;color:var(--body);text-decoration:none;
  padding:8px 12px;display:inline-flex;align-items:center;
  border-inline-start:1px solid var(--line)
}
.calnav a:first-child,.calseg a:first-child{border-inline-start:0}
.calnav a:hover,.calseg a:hover{background:var(--surface-hover);color:var(--ink)}
.calnav a.i{padding:8px 11px;font-size:14px;color:var(--muted)}
.calnav a.i:hover{color:var(--ink)}
.calseg a.on{background:var(--brand-2);color:var(--on-brand-2)}
.calseg a.on:hover{background:var(--brand-2);color:var(--on-brand-2)}

.wk ~ .cal-list,.mo ~ .cal-list{display:none}
.cal-list{display:block}

/* ---- week grid -----------------------------------------------------------
   A fixed row height (--wk-row) and a top pad (--wk-pad). Everything is placed
   against those with calc(): the hour label is CENTRED on its gridline
   (translateY(-50%)), and --wk-pad gives the first label ("07") room to sit
   above the first line without being clipped. --wk-hours and --wk-band-start
   (minutes) come from an inline style on .wk. */
.wk{
  --wk-row:2.75rem; --wk-pad:0.8rem;
  display:grid;grid-template-columns:3.4rem repeat(7,1fr);
  border:1px solid var(--line);border-radius:var(--radius-card);overflow:hidden;
  background:var(--card)
}
.wk-hd{
  padding:8px 5px;text-align:center;font-size:11.5px;font-weight:700;
  border-inline-start:1px solid var(--line);border-block-end:1px solid var(--line);
  background:var(--surface);color:var(--body);text-decoration:none
}
.wk-hd:first-child{border-inline-start:0}
.wk-hd small{display:block;font-weight:600;color:var(--muted);font-size:11px}
a.wk-hd:hover{background:var(--surface-hover);color:var(--ink)}
.wk-hd.today{background:var(--brand-2-soft);color:var(--ink)}
a.wk-hd.today:hover{background:var(--brand-2-soft);color:var(--ink)}
.wk-gut{position:relative;border-block-end:1px solid var(--line)}
.wk-gut span{
  position:absolute;inset-inline-end:6px;
  top:calc(var(--wk-pad) + var(--h,0) * var(--wk-row));transform:translateY(-50%);
  font-size:10.5px;color:var(--muted);font-variant-numeric:tabular-nums
}
.wk-lane{
  position:relative;
  min-height:calc(2 * var(--wk-pad) + var(--wk-hours,14) * var(--wk-row));
  border-inline-start:1px solid var(--line);border-block-end:1px solid var(--line);
  background-image:repeating-linear-gradient(to bottom,
    var(--line) 0 1px, transparent 1px var(--wk-row));
  background-position:0 var(--wk-pad);background-repeat:no-repeat;
  background-size:100% calc(var(--wk-hours,14) * var(--wk-row))
}
.wk-slot{
  position:absolute;overflow:hidden;min-height:1.1rem;
  top:calc(var(--wk-pad) + (var(--s,0) - var(--wk-band-start,420)) / 60 * var(--wk-row));
  height:calc(var(--d,60) / 60 * var(--wk-row));
  inset-inline-start:calc(2px + var(--lane,0) / var(--lanes,1) * 100%);
  width:calc(100% / var(--lanes,1) - 4px);
  border-radius:6px;padding:3px 5px;font-size:11px;line-height:1.3;
  background:var(--surface);color:var(--ink);text-decoration:none;
  border-inline-start:3px solid var(--cal-ink,var(--series-1))
}
a.wk-slot:hover{background:var(--surface-hover);color:var(--ink)}
.wk-slot.full{color:var(--muted)}
.wk-slot b{font-weight:700;display:block;font-variant-numeric:tabular-nums}
.wk-slot span{
  color:var(--muted);display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis
}

/* ---- month grid ---------------------------------------------------- */
.mo{
  border:1px solid var(--line);border-radius:var(--radius-card);
  overflow:hidden;background:var(--card)
}
.mo-wd{
  display:grid;grid-template-columns:repeat(7,1fr);
  background:var(--surface);color:var(--body);border-block-end:1px solid var(--line)
}
.mo-wd span{padding:6px 8px;font-size:11px;font-weight:700;text-align:center}
.mo-row{display:grid;grid-template-columns:repeat(7,1fr)}
.mo-cell{
  min-height:5.2rem;padding:6px 7px;display:flex;flex-direction:column;gap:4px;
  border-inline-start:1px solid var(--line);border-block-start:1px solid var(--line);
  background:var(--card);color:var(--body);text-decoration:none
}
.mo-cell:first-child{border-inline-start:0}
a.mo-cell:hover{background:var(--surface-hover);color:var(--ink)}
.mo-cell.out{background:var(--surface);color:var(--muted)}
a.mo-cell.out:hover{background:var(--surface-hover);color:var(--body)}
.mo-cell.today .mo-d{background:var(--brand-2);color:var(--on-brand-2)}
.mo-d{
  align-self:flex-start;font-size:12px;font-weight:700;min-width:1.4rem;
  padding:1px 5px;border-radius:var(--radius-pill);text-align:center
}
.mo-dots{display:flex;gap:4px;flex-wrap:wrap;margin-block-start:auto}
.mo-dot{width:8px;height:8px;border-radius:50%;flex:none;background:var(--cal-ink,var(--series-1))}
.mo-more{font-size:10.5px;color:var(--muted)}

.cal-empty{
  padding:24px;text-align:center;color:var(--muted);font-size:13.5px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-card)
}

@media (max-width:820px){
  .wk,.mo{display:none}
  .wk ~ .cal-list,.mo ~ .cal-list{display:block}
}

/* ======================================================================
   PORDASI results browse — public/pordasi.php

   One GET form: a search box (with a <datalist> fallback), a Group and a
   Sort <select>, a filter rail and a grouped list. Desktop lays the rail
   beside the results; below 860px the rail is a <details> that opens as a
   bottom sheet. Every state is a URL — app.js only saves a round trip.
   ====================================================================== */

.pd-browse{margin-block-start:22px}

.pd-top{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-block-end:16px}

.pd-find{position:relative;flex:1 1 320px;max-width:520px;display:flex;align-items:center;
  background:var(--card);border:1.5px solid var(--line-strong);
  border-radius:var(--radius-field)}
.pd-find:focus-within{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-tint-2)}
.pd-find-i{display:flex;padding-inline-start:12px;color:var(--meta)}
.pd-find input{flex:1;min-width:0;border:0;outline:0;background:transparent;
  font:inherit;font-size:15px;color:var(--ink);padding:11px 10px}
.pd-find input::placeholder{color:var(--meta)}
.pd-find-go{flex:none;border:0;background:transparent;color:var(--brand);
  font:inherit;font-weight:700;font-size:13px;padding:11px 14px;cursor:pointer}
.pd-find-go:hover{color:var(--brand-line)}

/* Group / Sort carry no caption — the option itself reads "Group by date". */
.pd-ctl{flex:0 0 auto}
.pd-ctl select{font:inherit;font-size:13.5px;color:var(--ink);background:var(--card);
  border:1px solid var(--line-strong);border-radius:var(--radius-field);
  padding:10px 12px;cursor:pointer;max-width:100%}
.pd-ctl select:focus{outline:0;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-tint-2)}

.pd-cols{display:grid;grid-template-columns:232px minmax(0,1fr);gap:24px;align-items:start}

.pd-cols-solo{grid-template-columns:minmax(0,1fr)}   /* no rail yet */

.pd-empty{padding:28px 6px;color:var(--muted);max-width:52ch}
.pd-empty-h{font-size:16px;font-weight:700;color:var(--ink);margin:0 0 6px}
.pd-empty p{margin:0}

/* an IHAA row links nowhere — the scoresheet is a link of its own */
.pd-row-static{cursor:default}
.pd-row-static:hover{background:none}
.pd-sheet{font-size:11px;color:var(--brand);white-space:nowrap;margin-inline-start:6px}
.pd-sheet:hover{color:var(--brand-line)}

/* ---- the rail --------------------------------------------------------- */
.pd-rail{font-size:13px}
.pd-rail > summary{display:none}
.pd-rail-b{display:flex;flex-direction:column;gap:2px}
.pd-facet{border-block-end:1px solid var(--line);padding:10px 0}
.pd-facet:first-of-type{padding-block-start:0}
.pd-facet > summary{display:flex;align-items:center;gap:8px;font-weight:700;color:var(--ink);
  font-size:13px;cursor:pointer;list-style:none;padding:3px 0}
.pd-facet > summary::-webkit-details-marker{display:none}
.pd-facet > summary::marker{content:''}
.pd-facet > summary::after{content:'';width:7px;height:7px;margin-inline-start:auto;flex:none;
  border-inline-end:1.5px solid var(--meta);border-block-end:1.5px solid var(--meta);
  transform:translateY(-2px) rotate(45deg);transition:transform .12s}
.pd-facet[open] > summary::after{transform:translateY(1px) rotate(-135deg)}
.pd-facet-n{display:inline-grid;place-items:center;min-width:17px;height:17px;padding:0 5px;
  border-radius:9px;background:var(--brand-2-soft);color:var(--brand-2-deep);font-size:11px}
.pd-facet-b{display:flex;flex-direction:column;gap:2px;padding-block-start:6px}
.pd-opt{display:flex;align-items:center;gap:9px;padding:6px;border-radius:6px;cursor:pointer}
.pd-opt:hover{background:var(--surface-hover);color:var(--ink)}
.pd-opt input{accent-color:var(--brand);width:15px;height:15px;flex:none}
.pd-opt-l{flex:1;min-width:0}
.pd-opt-n{color:var(--meta);font-size:12px}
.pd-rail-f{display:flex;align-items:center;justify-content:space-between;gap:10px;
  flex-wrap:wrap;padding-block-start:12px}
.pd-clear{font-size:12.5px;color:var(--brand);white-space:nowrap}
.pd-rail-f .btn{font-size:12.5px;padding:7px 14px}
.pd-rail-s{display:inline-flex;align-items:center;gap:8px}
.pd-rail-n{display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 5px;
  border-radius:9px;background:var(--brand-2-soft);color:var(--brand-2-deep);
  font-size:11px;font-weight:700}

/* ---- the results ----------------------------------------------------- */
.pd-main{min-width:0}
.pd-resbar{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin-block-end:10px}
.pd-count{font-size:13px;color:var(--muted)}
.pd-count b{color:var(--ink);font-weight:700}
.pd-chips{display:flex;gap:7px;flex-wrap:wrap;align-items:center}
.pd-x{font-size:14px;line-height:1;opacity:.7}

.pd-ghead{position:sticky;inset-block-start:0;z-index:3;display:flex;align-items:baseline;
  gap:10px;background:var(--page);color:var(--ink);font-size:14px;font-weight:700;
  padding:9px 2px 6px;margin:6px 0 0;border-block-end:1px solid var(--line-strong)}
.pd-ghead:first-of-type{margin-block-start:0}
.pd-gm{font-size:12px;font-weight:400;color:var(--muted)}

/* ---- the event list (search / filter lands here) --------------------- */
.pd-elist{border:1px solid var(--line);border-radius:12px;overflow:hidden;background:var(--card)}
.pd-ehead,.pd-erow{display:grid;
  grid-template-columns:minmax(0,1fr) 148px 92px 104px 72px 70px 72px;
  gap:10px;align-items:center;padding:11px 15px}
.pd-ehead{background:var(--surface);border-block-end:1px solid var(--line-strong);
  font-size:12px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--muted)}
html[lang="zh"] .pd-ehead{letter-spacing:0;text-transform:none}
.pd-erow{border-block-end:1px solid var(--line);color:var(--body);text-decoration:none}
.pd-erow:last-child{border-block-end:0}
.pd-erow:hover{background:var(--surface);color:var(--ink)}
.pd-en{color:var(--ink);font-weight:600;font-size:14px;min-width:0}
.pd-ecab{display:flex;gap:4px;flex-wrap:wrap}
.pd-ecab .pill{font-weight:600}
.pd-ecty,.pd-eloc{font-size:12.5px;color:var(--body)}
.pd-edt{font-size:12.5px;color:var(--body);font-variant-numeric:tabular-nums}
.pd-ejn{text-align:center;font-weight:700;color:var(--ink);font-size:15px;line-height:1.15}
.pd-ejn small{display:block;font-weight:400;color:var(--meta);font-size:10px}
.pd-ejn.match,.pd-ejn.match small{color:var(--brand-2-deep)}
.pd-ego{text-align:end;font-size:12px;font-weight:600;color:var(--brand);white-space:nowrap}
.pill.j{background:var(--brand-tint-2);color:var(--brand-text)}
.pill.d{background:var(--brand-2-soft);color:var(--brand-2-deep)}
.pill.h{background:var(--ok-bg);color:var(--ok)}

@media (max-width:820px){
  .pd-ehead{display:none}
  .pd-erow{grid-template-columns:minmax(0,1fr) auto;gap:5px 12px;padding:13px}
  .pd-en{grid-column:1/-1}
  .pd-ecab{grid-column:1;grid-row:2}
  .pd-edt{grid-column:2;grid-row:2;text-align:end}
  .pd-ecty{grid-column:1;grid-row:3;color:var(--muted)}
  .pd-eloc{grid-column:2;grid-row:3;text-align:end;color:var(--muted)}
  .pd-ejn{grid-column:1;grid-row:4;text-align:start;font-size:13px}
  .pd-ejn small{display:inline}
  .pd-ego{grid-column:2;grid-row:4;text-align:end}
}

.pd-list{display:flex;flex-direction:column;
  background:var(--card);border:1px solid var(--line);border-radius:12px;overflow:hidden}
.pd-list > .pd-exp:last-child{border-block-end:0}
.pd-row{display:grid;grid-template-columns:52px minmax(0,1fr) auto;gap:12px;
  align-items:center;padding:11px 14px;border-block-end:1px solid var(--line);
  color:var(--body);text-decoration:none}
.pd-row:hover{background:var(--surface);color:var(--ink)}
.pd-rd{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
.pd-rt{color:var(--ink);font-weight:600;font-size:14px;min-width:0}
.pd-rt .pill{margin-inline-start:6px;font-weight:600}
.pd-rsub{display:block;font-size:12px;font-weight:400;color:var(--muted);margin-block-start:2px}
.pd-rw{text-align:end;font-size:13px;color:var(--ink)}
.pd-re{display:block;font-size:11px;color:var(--muted)}

/* ---- a class / ride row that expands in place -------------------------- */
.pd-exp{border-block-end:1px solid var(--line)}
.pd-exp > summary.pd-row{border-block-end:0;list-style:none;cursor:pointer;
  padding-inline-start:30px;position:relative}
.pd-exp > summary.pd-row::-webkit-details-marker{display:none}
.pd-exp > summary.pd-row::marker{content:''}
.pd-exp > summary.pd-row::before{content:'';position:absolute;inset-inline-start:12px;
  inset-block-start:17px;width:7px;height:7px;border-inline-end:1.5px solid var(--meta);
  border-block-end:1.5px solid var(--meta);transform:rotate(-45deg);transition:transform .12s}
.pd-exp[open] > summary.pd-row::before{transform:rotate(45deg)}
.pd-exp[open] > summary.pd-row{background:var(--brand-tint);color:var(--ink)}
.pd-exp-b{padding:10px 14px 16px 30px;background:var(--card);border-block-start:1px solid var(--line)}
.pd-exp-t{font-size:12.5px}
.pd-exp-t th{font-size:10.5px}
.pd-exp-t td.sub2{color:var(--muted)}
.pd-src{font-size:11px}
.pd-exp-b .pd-full{display:inline-flex;align-items:center;min-height:44px;padding:11px 0}

/* ---- sponsored placement strip -------------------------------------- */
.pd-promo{margin:14px 0 22px}
.pd-promo-h{font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--meta);margin:0 0 8px}
html[lang="zh"] .pd-promo-h{letter-spacing:0;text-transform:none}
.pd-promo-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
.pd-promo-c{position:relative;display:flex;flex-direction:column;gap:6px;
  padding:14px 14px 13px;border:1px solid var(--line);border-radius:12px;
  background:var(--card);text-decoration:none;overflow:hidden;
  transition:border-color .12s,box-shadow .12s,transform .12s}
.pd-promo-c::before{content:'';position:absolute;inset-block-start:0;inset-inline:0;height:3px;
  background:var(--brand)}
.pd-promo-2::before{background:var(--accent-deep)}
.pd-promo-3::before{background:var(--ok)}
.pd-promo-c:hover{border-color:var(--brand-line,var(--line-strong));
  box-shadow:var(--shadow);transform:translateY(-1px)}
.pd-promo-tag{align-self:flex-start;font-size:10px;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase;color:var(--brand-text,var(--brand));background:var(--brand-tint-2);
  padding:3px 8px;border-radius:20px}
html[lang="zh"] .pd-promo-tag{letter-spacing:0;text-transform:none}
.pd-promo-t{font-size:14px;font-weight:700;color:var(--ink);line-height:1.3}
.pd-promo-x{font-size:12.5px;color:var(--body);line-height:1.45}
.pd-promo-cta{margin-block-start:auto;padding-block-start:4px;font-size:12.5px;font-weight:600;
  color:var(--brand)}

/* ---- admin-set banner images (one per view, swipe for more) --------- */
.pd-banners{display:flex;gap:12px;overflow-x:auto;scroll-snap-type:x mandatory;
  scrollbar-width:thin;padding-block-end:4px;-webkit-overflow-scrolling:touch}
.pd-banner{flex:0 0 100%;scroll-snap-align:start;display:block;border-radius:12px;
  overflow:hidden;border:1px solid var(--line);background:var(--surface);
  transition:box-shadow .12s,transform .12s}
.pd-banner:hover{box-shadow:var(--shadow);transform:translateY(-1px)}
.pd-banner img{display:block;width:100%;aspect-ratio:4/1;object-fit:cover}

/* ---- "browse by sport" tiles on the empty state -------------------- */
.pd-picks{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:4px 0 6px}
.pd-pick{position:relative;display:flex;flex-direction:column;gap:5px;min-height:96px;
  padding:15px 16px 14px;border:1px solid var(--line);border-radius:12px;background:var(--card);
  text-decoration:none;overflow:hidden;transition:border-color .12s,box-shadow .12s,transform .12s}
.pd-pick::before{content:'';position:absolute;inset-block-start:0;inset-inline:0;height:3px;
  background:var(--brand)}
.pd-pick-sj::before{background:var(--brand-line)}
.pd-pick-dr::before{background:var(--brand-2-deep)}
.pd-pick-ha::before{background:var(--ok)}
.pd-pick:hover{border-color:var(--brand-line,var(--line-strong));
  box-shadow:var(--shadow);transform:translateY(-1px)}
.pd-pick-t{font-size:15px;font-weight:700;color:var(--ink)}
.pd-pick-x{font-size:12.5px;color:var(--body);line-height:1.45}
.pd-pick-go{margin-block-start:auto;padding-block-start:4px;font-size:12.5px;font-weight:600;
  color:var(--brand)}

.pd-clubs{margin-block-start:30px;border-block-start:1px solid var(--line);padding-block-start:8px}
.pd-clubs > summary{font-size:14px;font-weight:700;color:var(--ink);cursor:pointer;
  padding:10px 0;list-style:none}
.pd-clubs > summary::-webkit-details-marker{display:none}
.pd-clubs > summary::marker{content:''}
.pd-clubs > summary::after{content:'+';margin-inline-start:8px;color:var(--meta)}
.pd-clubs[open] > summary::after{content:'–'}

/* ---- the custom autocomplete app.js draws over the box -------------- */
.pd-sug{position:absolute;inset-block-start:calc(100% + 6px);inset-inline:0;z-index:40;
  background:var(--card);border:1px solid var(--line-strong);border-radius:10px;
  box-shadow:var(--shadow);padding:6px;margin:0;list-style:none}
.pd-sug li{margin:0}
.pd-sug button{display:flex;width:100%;align-items:center;gap:10px;text-align:start;
  border:0;background:transparent;border-radius:7px;padding:9px 10px;cursor:pointer;
  font:inherit;color:var(--body)}
.pd-sug button:hover,.pd-sug button[aria-selected="true"]{background:var(--surface-hover);color:var(--ink)}
.pd-sug .pd-sug-n{display:block;font-weight:700;color:var(--ink);font-size:14px}
.pd-sug .pd-sug-m{display:block;font-size:12px;color:var(--muted)}
.pd-sug mark{background:var(--brand-2-soft);color:var(--brand-2-deep);border-radius:3px}
.pd-sug-c{margin-inline-start:auto;font-size:12px;color:var(--muted);white-space:nowrap}
.pd-sug-none{padding:12px 10px;font-size:13px;color:var(--muted)}

@media (min-width:861px){
  .pd-rail-f .btn{display:none}          /* desktop applies on change — the button is the phone path */
}

@media (max-width:860px){
  .pd-cols{grid-template-columns:minmax(0,1fr)}
  .pd-rail{order:-1}
  /* no JS: the rail is just an inline block above the results, always shown */
  .pd-rail:not(.js) > summary{display:none}
  /* with JS: a Filters button that opens the rail as a bottom sheet */
  .pd-rail.js > summary{display:inline-flex;align-items:center;gap:8px;list-style:none;
    min-height:44px;padding:9px 14px;border:1px solid var(--line-strong);
    border-radius:var(--radius-field);background:var(--card);color:var(--ink);
    font-weight:600;font-size:13.5px;cursor:pointer;box-sizing:border-box}
  .pd-rail.js > summary::-webkit-details-marker{display:none}
  .pd-rail.js > summary::marker{content:''}
  .pd-rail.js:not([open]) > .pd-rail-b{display:none}
  .pd-rail.js[open]{position:fixed;inset:0;z-index:200;background:var(--scrim)}
  .pd-rail.js[open] > summary{position:fixed;inset-block-start:12px;inset-inline-end:12px;z-index:202}
  .pd-rail.js[open] > .pd-rail-b{display:flex;position:fixed;z-index:201;inset-inline:0;inset-block-end:0;
    max-height:86vh;overflow:auto;background:var(--card);color:var(--body);
    border-radius:16px 16px 0 0;padding:18px 18px calc(18px + env(safe-area-inset-bottom))}
  .pd-rail-f .btn{min-height:44px}
  .pd-opt{min-height:44px}
  .pd-ctl{flex:1 1 100%}
  .pd-ctl select{width:100%;min-height:44px}
  .pd-find{flex-basis:100%;max-width:none}
  .pd-find input{min-height:44px}
  .pd-find-go{min-height:44px}
  .pd-facet > summary{min-height:44px}
  .pd-clear{display:inline-flex;align-items:center;min-height:44px}
  .pd-sheet{display:inline-flex;align-items:center;justify-content:center;min-height:44px;min-width:44px}
  .pd-clubs > summary{min-height:44px;box-sizing:border-box;display:flex;align-items:center}
  .pd-promo-row{grid-template-columns:1fr}
  .pd-picks{grid-template-columns:1fr}
  .pd-row{grid-template-columns:1fr auto;row-gap:2px;padding:12px 12px}
  .pd-exp > summary.pd-row{padding-inline-start:30px}
  .pd-rd{grid-row:1;grid-column:2;justify-self:end}
  .pd-rt{grid-row:1;grid-column:1}
  .pd-rw{grid-row:2;grid-column:1/-1;text-align:start;font-size:12px;color:var(--muted)}
  .pd-re{display:inline;color:var(--muted)}
  .pd-re::before{content:' · '}
}

/* ==========================================================================
   Competition revamp - the tab strip every page of an event carries, the class
   picker on the entry list, and the signatures on a published result.
   Tokens only; nothing here names a colour.
   ========================================================================== */

.comp-tabs{padding-block:10px;border-radius:var(--radius, 10px);margin-block-end:14px;border:1px solid var(--line)}
.comp-tabs .tab{text-decoration:none}

.tin.wide,.tin.acct{width:260px;max-width:100%;text-align:start}

.pick{position:relative}
.pick > summary{list-style:none;cursor:pointer}
.pick > summary::-webkit-details-marker{display:none}
.pickform{
  margin-block-start:8px;border:1px solid var(--line);border-radius:10px;background:var(--surface);
  padding:10px 12px;min-width:min(340px,86vw);display:grid;gap:8px;
}
.pickrow{display:flex;align-items:center;gap:10px;justify-content:space-between}
.pickrow > span:first-of-type{flex:1}
.pickfoot{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  border-block-start:1px solid var(--line);padding-block-start:8px;
}
.picktotal{font-weight:700}

.sigrow{
  display:flex;flex-wrap:wrap;gap:14px 20px;margin-block-start:14px;padding-block-start:12px;
  border-block-start:1px solid var(--line);
}
.sigtitle{
  flex:0 0 100%;font-size:11.5px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--meta);
}
.sig{margin:0;display:flex;flex-direction:column;gap:4px;min-width:140px}
.sig img{
  height:52px;width:auto;max-width:180px;background:var(--surface);border-radius:6px;
  border:1px solid var(--line);object-fit:contain;
}
.sig figcaption{display:flex;flex-direction:column;font-size:12.5px;line-height:1.3}
.sig figcaption span{font-size:11.5px;color:var(--meta)}

/* A competition that runs more than one sport groups its classes by sport. */
.sporthead{font-size:15px;font-weight:700;color:var(--brand-text);margin-block:18px 8px;letter-spacing:.02em}

/* The competitions hub: one row per competition, its facts on the left, its
   next steps on the right, stacking on a phone. */
.comp-row{display:flex;gap:12px 20px;justify-content:space-between;flex-wrap:wrap;padding-block:14px;border-block-end:1px solid var(--line)}
.comp-row:last-child{border-block-end:0}
.comp-main{flex:1 1 280px;min-width:0}
.comp-pills{display:flex;gap:6px;flex-wrap:wrap;margin-block-start:8px}
.comp-links{display:flex;gap:6px;flex-wrap:wrap;align-items:flex-start;flex:1 1 260px;justify-content:flex-end}

/* ---------- toast and dialog -------------------------------------------------
   A success message is a toast (note('ok') raises one), and a destructive choice is
   a dialog rather than the browser's confirm(). The host elements are drawn once by
   layout_foot(); public/assets/app.js opens and closes them. The same rules are kept in
   competition.css for the two phone pages, which do not load this file. */
#toast{position:fixed;left:50%;bottom:calc(20px + env(safe-area-inset-bottom,0px));transform:translate(-50%,20px);background:var(--ink);color:var(--page);padding:11px 18px;border-radius:30px;font-size:13.5px;font-weight:600;opacity:0;pointer-events:none;transition:.22s;z-index:99;max-width:calc(100% - 32px);text-align:center}
#toast.on{opacity:1;transform:translate(-50%,0)}
.scrim{position:fixed;inset:0;background:var(--scrim);display:none;align-items:center;justify-content:center;padding:16px;z-index:60}
.scrim.on{display:flex}
.dlg{background:var(--card);border-radius:var(--radius-card);max-width:460px;width:100%;padding:20px;display:flex;flex-direction:column;gap:12px;box-shadow:var(--shadow);max-height:90vh;overflow:auto}
.dlg h2{margin:0;font-size:17px}
.dlg p{margin:0}
.dlg .dlg-acts{display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ==========================================================================
   The public menu — inc/layout.php public_menu_markup()
   Grouped disclosures on a wide screen; one stacked "Menu" at 1040px and
   below, the width the signed-in shell already switches at. Each group is a
   details.navmenu so app.js gives it Escape and a tap outside for free.
   Selectors on the dark bar name .pub-bar so tests/contrast.php measures them
   against the ground they sit on; the panels are light and do not.
   ========================================================================== */
.pub-bar{gap:12px}
.pub-bar .pub-nav{display:flex;align-items:center;gap:2px;margin-inline-start:auto;flex-wrap:nowrap}
.pub-bar .pub-nav .navmenu.mega{display:block;position:relative}
.pub-bar .pub-nav .mega[open]::before{content:none}
.pub-bar .mega > summary,.pub-bar .pub-nav .plain,.pub-bar .pub-acts .plain{
  list-style:none;display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:8px 12px;
  border-radius:10px;cursor:pointer;font-size:14px;font-weight:600;text-decoration:none;
  color:rgba(255,255,255,.88);background:transparent}
.pub-bar .mega > summary::-webkit-details-marker{display:none}
.pub-bar .mega > summary::marker{content:""}
.pub-bar .mega > summary:hover,.pub-bar .mega[open] > summary,.pub-bar .pub-nav .plain:hover,.pub-bar .pub-acts .plain:hover{
  background:rgba(255,255,255,.10);color:#fff}
.pub-bar .mega .car{display:inline-flex;transition:transform .12s}
.pub-bar .mega[open] .car{transform:rotate(180deg)}
.pub-bar .pub-acts{display:flex;align-items:center;gap:6px}
.mega-panel{position:absolute;inset-block-start:calc(100% + 8px);inset-inline-start:0;z-index:60;
  width:min(660px,calc(100vw - 32px));background:var(--card);color:var(--body);
  border:1px solid var(--line-strong);border-radius:16px;box-shadow:var(--shadow);padding:16px}
.mega-explore .mega-panel{width:min(320px,calc(100vw - 32px))}
.mega-h{font-size:11.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin:0 0 10px}
.mg{display:grid;grid-template-columns:1fr 1fr;gap:2px}
.mg.one{grid-template-columns:1fr}
.mg .mi{display:flex;gap:12px;align-items:flex-start;min-height:44px;padding:9px 10px;border-radius:12px;
  text-decoration:none;color:var(--body);background:transparent}
.mg .mi:hover{background:var(--brand-tint-2);color:var(--body)}
.mg .mic{flex:none;display:grid;place-items:center;width:34px;height:34px;border-radius:10px;
  background:var(--brand-tint-2);color:var(--brand-text)}
.mg .mi b{display:block;font-size:14px;color:var(--ink);line-height:1.3}
.mg .mi small{display:block;font-size:12.5px;color:var(--muted);line-height:1.4;margin-block-start:2px}
.pubmenu > summary{list-style:none}
.pubmenu > summary::-webkit-details-marker{display:none}
.pubmenu > summary::marker{content:""}
.pub-bar .pubmenu > summary{display:inline-flex;align-items:center;min-height:44px;padding:8px 18px;cursor:pointer;
  border-radius:var(--radius-pill);border:1px solid rgba(255,255,255,.45);font-size:14px;font-weight:600;
  color:#fff;background:transparent}
.pub-bar .pubmenu[open] > summary{background:rgba(255,255,255,.14);color:#fff}
/* Hung from the bar, not the button: the language picker sits to the right of the button, so a panel aligned to the button would run off the left edge. */
.pub-bar .navmenu.pubmenu{position:static}
.pub-bar .pubmenu > .menupanel{inset-inline-start:auto;padding-block:14px;background:var(--card);border-radius:16px}
.pubmenu-panel{position:absolute;inset-block-start:calc(100% + 8px);inset-inline-end:0;z-index:60;
  width:min(360px,calc(100vw - 32px));max-height:min(78vh,640px);overflow-y:auto;
  background:var(--card);border:1px solid var(--line-strong);border-radius:16px;box-shadow:var(--shadow);
  padding:14px;display:flex;flex-direction:column;gap:14px}
.pm-group{display:flex;flex-direction:column}
.pubmenu-panel > .plain{display:flex;align-items:center;min-height:44px;padding:8px 10px;border-radius:12px;font-weight:700;color:var(--brand-text);text-decoration:none}
.pubmenu-panel > .plain:hover{background:var(--brand-tint-2);color:var(--brand-text)}
.pm-acts{display:flex;gap:10px;align-items:center;padding-block-start:12px;border-block-start:1px solid var(--line)}
.pm-acts .plain{display:inline-flex;align-items:center;min-height:44px;padding:8px 12px;font-weight:700;
  color:var(--brand-text);text-decoration:none}
.pm-acts .pub-app{flex:1;justify-content:center}
@media (max-width:1040px){
  .pub-bar .pub-nav,.pub-bar .pub-acts{display:none}
  .pub-bar .pubmenu{margin-inline-start:auto}
  /* A signed-in visitor's name chip and app button would wrap the bar onto a second row; the hero already carries "Open the app". */
  .pub-bar .pub-who,.pub-bar .pub-app{display:none}
  .pub-bar .pub-acts{display:none}
}

/* ==========================================================================
   News: the editor (app/news_edit.php), the list and the article (public/news*.php)
   ========================================================================== */

.newsform input[type=checkbox],.newsform input[type=radio]{width:auto;flex:none;margin:0}
.ph-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:14px}
.ph{border:1px solid var(--line);border-radius:8px;padding:10px;display:flex;flex-direction:column;gap:8px;background:var(--surface)}
.ph img{width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:5px;display:block;background:var(--line)}
.ph label{display:flex;flex-direction:column;gap:3px;font-size:13px}
.ph .row{display:flex;gap:10px;align-items:center;flex-wrap:wrap;font-size:13px}
.share-row{display:flex;gap:10px;flex-wrap:wrap}
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px}
.cards figure{margin:0;display:flex;flex-direction:column;gap:8px}
.cards img{width:100%;border-radius:6px;border:1px solid var(--line);display:block}

.newsgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:22px}
.newscard{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:10px;overflow:hidden;
  background:var(--surface);color:inherit;text-decoration:none}
.newscard:hover{border-color:var(--brand-2);box-shadow:var(--shadow)}
.newscard .im{aspect-ratio:16/9;background:var(--brand-tint-2);display:block;width:100%;object-fit:cover}
.newscard .tx{padding:16px 18px 18px;display:flex;flex-direction:column;gap:8px}
.newscard h2{font-size:19px;line-height:1.25;margin:0}
.newscard p{margin:0;color:var(--muted);font-size:14.5px}
.pager{display:flex;gap:10px;margin-block-start:26px;align-items:center}

.article{max-width:46rem;margin-inline:auto}
.article h1{font-size:clamp(26px,4vw,38px);line-height:1.15;margin:0 0 10px;text-wrap:balance}
.article .meta{color:var(--muted);font-size:14px;margin-block-end:20px}
.article .lede{font-size:19px;color:var(--muted);margin:0 0 22px}
.article p{font-size:17px;line-height:1.65;margin:0 0 16px}
.article figure{margin:0 0 22px}
.article img{width:100%;height:auto;border-radius:8px;display:block}
.article figcaption{font-size:13px;color:var(--muted);margin-block-start:6px}
.sharebar{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-block-start:28px;padding-block-start:18px;border-top:1px solid var(--line)}
.newsstats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-block-end:16px}
.newsstat{border:1px solid var(--line);border-radius:10px;padding:14px 16px;background:var(--surface);display:flex;flex-direction:column;gap:4px}
.newsstat b{font-size:28px;line-height:1;font-variant-numeric:tabular-nums}
.newsstat span{font-size:12.5px;color:var(--muted)}
.newsstat.warn b{color:var(--warn)}
.newslog{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.newslog li{display:flex;gap:10px;justify-content:space-between;flex-wrap:wrap;font-size:14px}
/* wg:start */
.wg{max-width:52rem}
.wg h2{font-size:19px;margin:28px 0 10px;text-wrap:balance}
.wg-lede{font-size:17px;color:var(--muted);margin:0 0 6px;max-width:62ch}
.wg-list{margin:0;padding-left:20px;display:flex;flex-direction:column;gap:7px;max-width:64ch}
.wg-table table{border-collapse:collapse;width:100%;font-size:14.5px}
.wg-table th,.wg-table td{text-align:left;vertical-align:top;padding:8px 10px;border-bottom:1px solid var(--line)}
.wg-table th{width:11rem;font-weight:600;color:var(--muted)}
.wg-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px}
.wg-pair{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:16px}
.wg figure{margin:0;display:flex;flex-direction:column;gap:6px}
.wg figure img{width:100%;height:auto;display:block;border-radius:6px;border:1px solid var(--line)}
.wg figcaption{font-size:13px;color:var(--muted)}
.wg-bad img{outline:3px solid var(--stop);outline-offset:-3px}
.wg-good img{outline:3px solid var(--ok);outline-offset:-3px}
.wg-ref{font-size:12.5px;color:var(--muted);margin-block-start:26px}
/* wg:end */
/* Terms and Conditions (public/terms.php) and the tick on the registration form */
.terms{max-width:46rem;margin-inline:auto}
.terms h1{font-size:clamp(26px,4vw,36px);line-height:1.15;margin:0 0 8px}
.terms h2{font-size:19px;margin:26px 0 8px;text-wrap:balance}
.terms p,.terms li{font-size:16px;line-height:1.65}
.terms ul{display:flex;flex-direction:column;gap:8px;padding-left:20px}
.terms-meta{color:var(--muted);font-size:14px;margin:0 0 18px}
.terms-toc{border:1px solid var(--line);border-radius:10px;padding:14px 18px;margin-block-end:8px;background:var(--surface)}
.terms-toc ol{margin:0;padding-left:20px;columns:2 16rem;column-gap:28px}
.terms-toc li{font-size:14.5px;padding-block:2px}
.form .terms-accept{flex-direction:row;align-items:flex-start;gap:10px}
.form .terms-accept input{width:auto;flex:none;margin:3px 0 0}
.form .terms-accept span{text-transform:none;letter-spacing:0;font-size:14px;font-weight:400;white-space:normal;min-width:0}
.profile-sports{border:1px solid var(--line);border-radius:8px;padding:10px 14px;display:flex;flex-direction:column;gap:6px;margin:0}
.profile-sports legend{padding:0 6px;font-size:13px;color:var(--muted)}
.clubbox{position:relative;display:flex;flex-direction:column;gap:8px}
.clubbox-l{font-size:13px;color:var(--muted)}
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chip{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);border-radius:999px;padding:4px 6px 4px 12px;background:var(--surface);font-size:14px}
.chip button{border:0;background:transparent;cursor:pointer;font-size:16px;line-height:1;color:var(--muted);padding:2px 6px;border-radius:999px}
.chip button:hover{color:var(--ink)}
.clubmenu{list-style:none;margin:0;padding:4px;position:absolute;inset-inline:0;top:100%;z-index:20;background:var(--surface);border:1px solid var(--line);border-radius:8px;box-shadow:var(--shadow);max-height:16rem;overflow:auto}
.clubmenu li{padding:8px 10px;border-radius:6px;cursor:pointer;display:flex;flex-direction:column;gap:1px;font-size:14px}
.clubmenu li:hover,.clubmenu li:focus{background:var(--brand-tint-2);color:var(--ink);outline:none}
.clubmenu small{color:var(--muted);font-size:12px}
.clubmenu .clubadd{font-weight:600}
.t.detail th{width:14rem;text-align:left;font-weight:600;color:var(--muted);vertical-align:top}
.t.detail td{vertical-align:top}


/* ==========================================================================
   The landing page — public/index.php and inc/landing.php
   Every colour is a token; white-on-dark alphas are the ones .pub-hero uses.
   ========================================================================== */
.pub-head .lp-hero{position:relative;z-index:1;display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:44px;align-items:center;padding-block:24px 60px}
/* The front page's header carries the owner's hero picture: navy with a soft gold light at the top right, dark and even on the left where the headline sits. It replaces the CSS glow, whose edge showed. Scoped by :has() so every other public page keeps its plain band. */
:root[data-theme="tovar"] .pub-head:has(.lp-hero){background:url("landing/hero-bg.webp") right top/cover no-repeat,var(--hero)}
:root[data-theme="tovar"] .pub-head:has(.lp-hero)::after{display:none}
/* On a phone the picture is scaled up until its gold light floods the whole header. Plain navy there. */
@media (max-width:900px){:root[data-theme="tovar"] .pub-head:has(.lp-hero){background:var(--hero)}}
.lp-hero-copy{min-width:0}
.pub-head .lp-hero .lp-eyebrow{font-size:12.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--accent)}
.pub-head .lp-hero h1{color:#fff;font-size:clamp(28px,4.2vw,46px);font-weight:700;line-height:1.15;margin-block-start:12px;max-width:18ch}
.pub-head .lp-hero .lp-lede{color:rgba(255,255,255,.80);font-size:16.5px;line-height:1.6;margin-block-start:16px;max-width:56ch}
.pub-head .lp-hero .lp-lede .lp-free{color:var(--accent);font-weight:700;white-space:nowrap}
.lp-cta{display:flex;flex-wrap:wrap;gap:12px;margin-block-start:26px;align-items:center}
.lp-btn{min-height:48px;padding:12px 26px;font-size:15px;font-weight:700;justify-content:center}
.pub-head .lp-hero .lp-btn-line,.lp-final .lp-btn-line{display:inline-flex;align-items:center;justify-content:center;
  min-height:48px;padding:12px 22px;border-radius:var(--radius-pill);font-size:15px;font-weight:600;
  text-decoration:none;color:#fff;border:1px solid rgba(255,255,255,.45);background:transparent}
.pub-head .lp-hero .lp-btn-line:hover,.lp-final .lp-btn-line:hover{background:rgba(255,255,255,.10);color:#fff}
.pub-head .lp-hero .lp-signin{margin-block-start:8px;font-size:14px;color:rgba(255,255,255,.74)}
.pub-head .lp-hero .lp-signin a{color:#fff;font-weight:700;text-decoration:underline;text-underline-offset:3px;
  display:inline-block;min-width:44px;padding:12px 4px;text-align:center}
.pub-head .lp-hero .lp-signin a:hover{color:var(--accent)}
.pub-head .lp-hero .lp-sports{margin-block-start:10px;padding-block-start:16px;border-block-start:1px solid rgba(255,255,255,.14)}
.pub-head .lp-hero .lp-sports-h{display:block;font-size:12.5px;font-weight:600;color:rgba(255,255,255,.74)}
.pub-head .lp-hero .lp-soon-h{margin-block-start:14px}
.pub-head .lp-hero .lp-sports ul{list-style:none;display:flex;flex-wrap:wrap;gap:8px;margin:10px 0 0;padding:0}
.pub-head .lp-hero .lp-sports li{font-size:13px;font-weight:600;color:#fff;padding:5px 12px;border-radius:20px;
  background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.18)}
.pub-head .lp-hero .lp-sports li:has(a){padding:0;background:transparent;border-color:transparent}
.pub-head .lp-hero .lp-sports li a{display:block;padding:5px 12px;border-radius:20px;color:#fff;text-decoration:none;
  background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.18)}
.pub-head .lp-hero .lp-sports li a:hover,.pub-head .lp-hero .lp-sports li a:focus-visible{color:#fff;background:rgba(255,255,255,.18)}
.pub-head .lp-hero .lp-sports .lp-soon-l li{background:transparent;border-style:dashed;border-color:rgba(255,255,255,.34);color:rgba(255,255,255,.86)}

/* The stage: pieces that float out of step, and change scene on a timer. */
.stage{position:relative;min-width:0}
.stage-box{position:relative;aspect-ratio:1.7/1;max-width:560px;margin-inline-start:auto}
.stage .burst{display:none;position:absolute;inset-inline-end:2%;inset-block-start:4%;width:56%;aspect-ratio:1;background:var(--brand-2);opacity:.9;
  clip-path:polygon(50% 0,60% 14%,76% 8%,78% 25%,94% 28%,86% 43%,100% 55%,84% 63%,88% 80%,71% 79%,64% 95%,50% 84%,36% 95%,29% 79%,12% 80%,16% 63%,0 55%,14% 43%,6% 28%,22% 25%,24% 8%,40% 14%)}
.stage .scene{position:absolute;inset:0;display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);grid-template-rows:1fr auto;gap:10px 14px;align-items:center;opacity:0;visibility:hidden;transition:opacity .5s ease,visibility 0s linear .5s}
.stage .scene.on{opacity:1;visibility:visible;transition-delay:0s}
.stage .el{min-width:0;opacity:0;transform:translateY(14px);transition:opacity .6s ease,transform .6s ease}
.stage .scene.on .el{opacity:1;transform:none}
.stage .scene.on .sc-photo{transition-delay:.18s}
.stage .scene.on .sc-card{transition-delay:.08s}
.stage .scene.on .sc-chip{transition-delay:.3s}
/* The photograph in front, the drawing of the function behind it: the photo already shows the app on a device. */
/* Side by side: the photo takes the left column, the drawing the right, the chip sits under the drawing. */
.stage .sc-photo{grid-column:1;grid-row:1/3;align-self:stretch;min-height:0}
.stage .sc-photo img,.stage .sc-photo .lp-ph{display:block;width:100%;height:100%;object-fit:cover;border-radius:18px;border:4px solid var(--card);box-shadow:var(--shadow)}
.stage .sc-card{grid-column:2;grid-row:1;align-self:end}
.stage .nophoto .sc-card{grid-column:1/-1}
.stage .sc-card .in{background:var(--card);border:1px solid var(--line-strong);border-radius:16px;box-shadow:var(--shadow);overflow:hidden;line-height:0}
.stage .sc-chip{grid-column:2;grid-row:2;justify-self:start;align-self:start}
.stage .nophoto .sc-chip{grid-column:1/-1}
.pub-head .stage .sc-chip .in{background:var(--brand-2);color:var(--on-brand-2);font-weight:700;font-size:13px;
  padding:8px 14px;border-radius:999px;box-shadow:var(--shadow);white-space:nowrap}
.stage[data-float="1"] .sc-card .in{animation:lpBobA 3.4s ease-in-out infinite}
.stage[data-float="1"] .sc-chip .in{animation:lpBobB 2.9s ease-in-out .5s infinite}
.stage[data-float="1"] .burst{animation:lpSpin 40s linear infinite}
@keyframes lpBobA{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}
@keyframes lpBobB{0%,100%{transform:translateY(0)}50%{transform:translateY(8px)}}
@keyframes lpSpin{to{transform:rotate(360deg)}}
.stage-cap{position:relative;min-height:112px;margin-block-start:14px;max-width:560px;margin-inline-start:auto}
.stage .cap{position:absolute;inset:0;opacity:0;visibility:hidden;transition:opacity .4s ease,visibility 0s linear .4s}
.stage .cap.on{opacity:1;visibility:visible;transition-delay:0s}
.pub-head .stage .cap-k{display:block;font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--accent)}
.pub-head .stage .cap b{display:block;margin-block-start:4px;font-size:19px;line-height:1.3;color:#fff}
.pub-head .stage .cap p{margin-block-start:4px;font-size:14.5px;line-height:1.5;color:rgba(255,255,255,.80)}
.stage .dots{display:flex;max-width:560px;margin-inline-start:auto}
.stage .dot{position:relative;width:44px;height:44px;border:0;background:transparent;cursor:pointer;padding:0}
.stage .dot::before{content:"";position:absolute;inset-inline:12px;inset-block-start:calc(50% - 4px);height:8px;border-radius:4px;
  background:rgba(255,255,255,.35);transition:background .2s}
.stage .dot[aria-current="true"]::before{background:var(--brand-2)}
.stage .dot:hover::before{transform:scaleY(1.5)}

/* Illustrations — SVG drawn from the page's own tokens (inc/landing.php). */
.vis{display:block;width:100%;height:auto;max-width:100%}
.vis text{font-family:inherit;fill:var(--ink)}
.vis .v-card{fill:var(--card);stroke:var(--line-strong)}
.vis .v-t{font-size:16px;font-weight:700}
.vis .v-t2{font-size:14px;font-weight:700}
.vis .v-tx,.vis .v-stx{font-size:13px;font-weight:600}
.vis .v-m,.vis .v-m text{font-size:12px;fill:var(--muted);font-weight:600}
.vis .v-grid line{stroke:var(--line);stroke-width:1}
.vis .v-line2 line{stroke:var(--line-strong)}
.vis .v-line{fill:none;stroke:var(--brand);stroke-width:3;stroke-linejoin:round;stroke-linecap:round}
.vis .v-area{fill:var(--brand-tint-2);stroke:none}
.vis .v-dot circle{fill:var(--card);stroke:var(--brand);stroke-width:2.5}
.vis .v-hot{fill:var(--brand-2);stroke:var(--card);stroke-width:3}
.vis .v-pill{fill:var(--brand-tint-2)}
.vis .v-pt{font-size:12px;font-weight:700;fill:var(--brand-text)}
.vis .v-tag{fill:var(--brand-2)}
.vis .v-tagt{font-size:12.5px;font-weight:700;fill:var(--on-brand-2)}
.vis .v-row{fill:var(--surface);stroke:var(--line)}
.vis .v-row.on{fill:var(--brand-tint-2);stroke:var(--brand)}
.vis .v-av{fill:var(--brand);opacity:.85}
.vis .v-track{fill:var(--surface-hover)}
.vis .v-fill{fill:var(--brand)}
.vis .c-book{fill:var(--brand);opacity:.9}
.vis .c-free{fill:var(--surface);stroke:var(--line-strong);stroke-dasharray:4 3}
.vis .c-pick{fill:var(--brand-2);stroke:var(--brand-2)}
.vis .v-pt2{font-size:12.5px;font-weight:700;fill:var(--on-brand-2)}
.vis .v-step rect{fill:var(--surface);stroke:var(--line-strong)}
.vis .v-step rect.last{fill:var(--brand-tint-2);stroke:var(--brand)}
.vis .v-arrow{stroke:var(--muted);stroke-width:2;fill:none;stroke-linecap:round}
.vis .v-ok{fill:var(--ok-bg)}
.vis .v-okt{font-size:12px;font-weight:700;fill:var(--ok)}
.vis .v-wait{fill:var(--warn-bg)}
.vis .v-waitt{font-size:12px;font-weight:700;fill:var(--warn)}
.vis .t-out{fill:var(--surface);stroke:var(--brand);stroke-width:2.5}
.vis .t-hit{fill:var(--brand-2)}
.vis .t-miss{stroke:var(--muted);stroke-width:3;stroke-linecap:round}
.vis .s-box{fill:var(--surface);stroke:var(--line-strong)}
.vis .s-box.last{fill:var(--brand-tint-2);stroke:var(--brand)}
.vis .sig{fill:none;stroke:var(--brand);stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
.vis .e-card{fill:var(--surface);stroke:var(--line-strong)}
.vis .stamp{fill:none;stroke:var(--ok);stroke-width:2.5}
.vis .stampt{font-size:13px;font-weight:700;fill:var(--ok)}
.vis .sw{fill:var(--brand-2)}
.vis .sw-k{fill:var(--card)}
.vis .lv-phone{fill:var(--surface);stroke:var(--ink);stroke-width:3}
.vis .lv-head{fill:var(--brand)}
.vis .lv-ht{font-size:13px;font-weight:700;fill:var(--card)}
.vis .lv-hm{font-size:11.5px;font-weight:600;fill:var(--card);opacity:.85}
.vis .lv-sem{fill:var(--warn-bg)}
.vis .lv-semt{font-size:10.5px;font-weight:700;fill:var(--warn)}
.vis .lv-fin{fill:var(--ok-bg)}
.vis .lv-fint{font-size:11px;font-weight:700;fill:var(--ok)}
.vis .lv-star{fill:var(--brand-2);stroke:none}
.vis .lv-btn{fill:var(--brand-2)}
.vis .lv-btnt{font-size:13px;font-weight:700;fill:var(--on-brand-2)}

/* A picture that has not arrived yet, at its final shape. */
.lp-ph{display:grid;place-items:center;width:100%;max-width:100%;border-radius:14px;
  background:repeating-linear-gradient(135deg,var(--surface) 0 14px,var(--surface-hover) 14px 28px);border:1px dashed var(--line-strong)}
.lp-ph span{font-size:12px;font-weight:600;color:var(--muted);background:var(--card);padding:4px 10px;border-radius:20px}

/* Sections */
.pub-main.lp-main{padding-block-start:8px;overflow-x:clip}
.lp-sec{padding-block:56px 8px}
.lp-sec-h{max-width:720px;margin-block-end:26px}
.lp-sec-h h2{font-size:clamp(22px,2.8vw,30px);font-weight:700;color:var(--ink);line-height:1.25}
.lp-sec-h p{margin-block-start:10px;font-size:16px;line-height:1.6;color:var(--body)}
.lp-ic{display:inline-grid;place-items:center;width:42px;height:42px;flex:none;border-radius:12px;background:var(--brand-tint-2);color:var(--brand)}
.lp-list{list-style:none;margin:14px 0 0;padding:0;display:flex;flex-direction:column;gap:8px}
.lp-list li{position:relative;padding-inline-start:20px;font-size:14.5px;line-height:1.5;color:var(--body)}
.lp-list li::before{content:"";position:absolute;inset-inline-start:2px;inset-block-start:.55em;width:7px;height:7px;border-radius:50%;background:var(--brand-2)}
.lp-small{margin-block-start:12px;font-size:12.5px;color:var(--muted)}

/* Roles, one slide each */
.slides .tabs{display:flex;gap:8px;flex-wrap:wrap;margin-block-end:16px}
.slides .tab{min-height:44px;padding:8px 18px;border-radius:999px;border:1px solid var(--line-strong);background:var(--card);
  color:var(--ink);font:inherit;font-size:14.5px;font-weight:600;cursor:pointer}
.slides .tab:hover{background:var(--brand-tint-2);color:var(--ink)}
.slides .tab[aria-selected="true"]{background:var(--brand-2);border-color:var(--brand-2);color:var(--on-brand-2);font-weight:700}
.slide-list{display:flex;flex-direction:column;gap:16px}
.slide{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);gap:36px;align-items:center;background:var(--card);
  border:1px solid var(--line);border-radius:18px;padding:28px;box-shadow:var(--shadow)}
.js .slide[hidden]{display:none}
html:not(.js) .slides .tabs,html:not(.js) .slide-nav{display:none}
.slide h3{font-size:24px;font-weight:700;color:var(--ink)}
.slide .role-s{margin-block-start:10px;font-size:15px;font-weight:600;color:var(--ink);line-height:1.45}
.lp-how{padding-block-start:16px;font-size:13px;font-weight:600;line-height:1.45}
.lp-how::before{content:"";display:inline-block;width:8px;height:8px;border-radius:50%;margin-inline-end:8px;vertical-align:1px;background:currentColor}
.lp-how-ok{color:var(--ok)}
.lp-how-wait{color:var(--warn)}
.lp-how-badge{color:var(--brand-text)}
.lp-role-a{display:inline-flex;align-items:center;gap:4px;min-height:44px;margin-block-start:8px;font-size:14px;font-weight:700;
  color:var(--brand-text);text-decoration:none}
.lp-role-a:hover{color:var(--ink);text-decoration:underline}
.lp-role-a svg{transform:rotate(-90deg)}
[dir="rtl"] .lp-role-a svg{transform:rotate(90deg)}
.slide-tx,.slide-vis{margin:0;min-width:0}
.slide-vis figcaption{margin-block-start:8px;font-size:12.5px;color:var(--muted);text-align:center}
.slide-nav{display:flex;align-items:center;justify-content:center;gap:16px;margin-block-start:16px}
.slide-nav .nav-btn{display:grid;place-items:center;width:44px;height:44px;border-radius:50%;border:1px solid var(--line-strong);
  background:var(--card);color:var(--ink);font-size:22px;line-height:1;cursor:pointer}
.slide-nav .nav-btn:hover{background:var(--brand-tint-2);color:var(--ink)}
.slide-nav .counter{font-size:14px;font-weight:600;color:var(--muted);min-width:7ch;text-align:center}

/* One path, and the news strip */
.lp-flow-pics{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-block-end:22px}
.lp-flow-pics figure{margin:0}
.lp-flow-pics img,.lp-flow-pics .lp-ph{display:block;width:100%;height:auto;border-radius:14px;aspect-ratio:3/2;object-fit:cover}
.lp-flow-pics figcaption{margin-block-start:8px;font-size:13px;font-weight:600;color:var(--muted)}
.lp-flow{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:14px}
.lp-flow li{display:flex;flex-direction:column;gap:10px;background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);padding:18px}
.lp-flow b{font-size:15px;color:var(--ink)}
.lp-flow p{margin-block-start:6px;font-size:14px;line-height:1.55;color:var(--body)}
.lp-n{display:inline-grid;place-items:center;width:32px;height:32px;border-radius:50%;flex:none;background:var(--brand);color:#fff;font-weight:700;font-size:14px}
.lp-note{display:flex;gap:8px;align-items:flex-start;margin-block-start:16px;padding:12px 16px;border-radius:12px;background:var(--info-bg);color:var(--info);font-size:14px;line-height:1.5}
.lp-note svg{flex:none;margin-block-start:2px}
.news{margin-block-start:34px}
/* The signed-in menu on a phone: the same full-screen navy sheet as the front page's
   menu, under the bar, instead of a small panel hung under the button. The burger
   stays on top and reads as a cross while it is open; the bar's other controls
   stay above the sheet so the language and sign-out are still reachable. */
@media (max-width:1040px){
  .topbar > *:not(.navmenu){position:relative;z-index:70}
  .topbar .navmenu > .burger{position:relative;z-index:70}
  .topbar .navmenu > .menupanel{position:fixed;inset:0;width:auto;max-height:none;border:0;border-radius:0;
    box-shadow:none;background:var(--hero);padding:84px 16px calc(16px + env(safe-area-inset-bottom));
    overflow-y:auto;z-index:60}
  .topbar .navmenu:not([open]) > .menupanel{display:none}
  .topbar .navmenu[open]::before{display:none}
  body:has(.topbar .navmenu[open]){overflow:hidden}
  .topbar .menupanel .nav a{min-height:54px;font-size:17px}
  .topbar .menupanel .nav-account{margin-block-start:10px;border-block-start:1px solid rgba(255,255,255,.14)}
}

/* A page that is switched off for now (inc/coming_soon.php). */
.comingsoon{max-width:44rem;margin-inline:auto}

/* A value that is shown, not edited — reads as text, so nobody expects to change it. */
.static-val{display:flex;flex-direction:column;gap:4px}
.static-val > b{font-size:16px;font-weight:600;color:var(--ink)}
.static-val > .lbl{font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
html[lang="zh"] .static-val > .lbl{letter-spacing:0;text-transform:none;font-size:13px}

/* Show/Hide inside a password field (app.js wirePwToggle). */
.pw{position:relative;display:block;width:100%}
.pw > input{width:100%;box-sizing:border-box;padding-inline-end:84px}
.pw-btn{position:absolute;inset-block:0;inset-inline-end:0;min-width:76px;min-height:44px;padding:0 14px;background:transparent;border:0;border-radius:0 6px 6px 0;color:var(--brand-text);font:inherit;font-size:14px;font-weight:700;cursor:pointer}
.pw-btn:hover{background:var(--surface-hover);color:var(--ink)}
.pw-btn:focus-visible{outline:2px solid var(--brand-2);outline-offset:-2px}

/* Searchable select (app.js wireSearchSelect). The real <select> stays in the form, hidden. */
.ss{position:relative;display:block;width:100%}
.ss-in{width:100%;box-sizing:border-box;min-height:44px;padding:9px 40px 9px 12px;background:var(--card);color:var(--ink);border:1px solid var(--line-strong);border-radius:6px;font:inherit;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 14px center}
.ss-list{position:absolute;z-index:30;inset-inline:0;top:calc(100% + 4px);max-height:min(60vh,320px);overflow-y:auto;margin:0;padding:6px;list-style:none;background:var(--card);border:1px solid var(--line-strong);border-radius:10px;box-shadow:var(--shadow-md)}
.ss-list li[role="option"]{padding:12px 10px;border-radius:8px;font-size:14.5px;line-height:1.35;color:var(--ink);cursor:pointer;overflow-wrap:anywhere}
.ss-list li[role="option"]:hover,.ss-list li.on{background:var(--surface-hover);color:var(--ink)}
.ss-list li[aria-selected="true"]{font-weight:700}
.ss-g{padding:10px 10px 4px;font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.ss-none{padding:12px 10px;color:var(--muted)}

.news-h{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.news-h h3{font-size:20px;font-weight:700;color:var(--ink);margin-block-end:12px}
.news-all{font-size:14px;font-weight:700;color:var(--brand-text);text-decoration:none;display:inline-flex;align-items:center;min-height:44px}
.ncard .nlink{color:inherit;text-decoration:none}
.ncard .nlink:hover{text-decoration:underline}
.marquee{overflow:hidden;border-radius:14px;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent);mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent)}
.marquee .track{list-style:none;margin:0;padding:4px 0;display:flex;gap:14px;width:max-content;animation:lpRun 50s linear infinite}
.marquee:hover .track,.marquee:focus-within .track,.marquee:focus .track{animation-play-state:paused}
@keyframes lpRun{from{transform:translateX(-50%)}to{transform:translateX(0)}}
.ncard{flex:none;width:410px;display:flex;gap:14px;align-items:stretch;background:var(--card);border:1px solid var(--line);border-radius:14px;padding:16px;box-shadow:var(--shadow-sm)}
.ncard .nph{flex:none;width:112px}
.ncard .nph img,.ncard .nph .lp-ph{display:block;width:112px;height:112px;object-fit:cover;border-radius:10px}
.ncard .nph .lp-ph span{font-size:10px;padding:2px 6px}
.ncard .nbody{display:flex;flex-direction:column;gap:6px;min-width:0}
.ncard b{font-size:15px;color:var(--ink);line-height:1.35}
.ncard p{font-size:13.5px;line-height:1.5;color:var(--body)}
.ntag{align-self:flex-start;font-size:12px;font-weight:700;padding:2px 10px;border-radius:20px}
.ntag.up{background:var(--ok-bg);color:var(--ok)}
.ntag.soon{background:var(--warn-bg);color:var(--warn)}

/* Modules */
.lp-mod{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);gap:40px;align-items:center;padding-block:22px}
.lp-mod-rev .lp-mod-tx{order:2}
.lp-mod h3,.lp-intl h3{font-size:21px;font-weight:700;color:var(--ink)}
.lp-mod-tx > p,.lp-intl-tx > p{margin-block-start:10px;font-size:15.5px;line-height:1.6;color:var(--body)}
.lp-shot{margin:0;border-radius:12px;overflow:hidden;background:var(--card);border:1px solid var(--line-strong);box-shadow:var(--shadow)}
.lp-shot img,.lp-shot .lp-ph{display:block;width:100%;height:auto;border-radius:0}
.lp-intl{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);gap:36px;align-items:center;margin-block:10px 22px;
  background:var(--card);border:1px solid var(--line);border-radius:18px;padding:26px;box-shadow:var(--shadow)}
.lp-kick{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--brand-text)}
.lp-intl h3{margin-block-start:6px}
.lp-phone{margin:0 auto;width:min(290px,80%);border-radius:30px;padding:10px;background:var(--ink);box-shadow:var(--shadow)}
.lp-phone img,.lp-phone .lp-ph{display:block;width:100%;height:auto;border-radius:22px}
.lp-share{grid-template-columns:minmax(0,.9fr) minmax(0,1.3fr)}
.share-cards{display:flex;gap:14px;align-items:flex-end;justify-content:center}
.phone-card{margin:0;flex:1 1 0;min-width:0;max-width:200px}
.phone-card img,.phone-card .lp-ph{display:block;width:100%;height:auto;border-radius:16px;border:1px solid var(--line-strong);box-shadow:var(--shadow)}
.phone-card:nth-child(2){transform:translateY(-18px)}
.phone-card figcaption{margin-block-start:8px;font-size:12.5px;font-weight:600;color:var(--muted);text-align:center}
.lp-share-note{grid-column:1/-1;margin:0}
.lp-mod-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;margin-block-start:26px}
.lp-mini{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);padding:20px}
.lp-mini h3{margin-block-start:12px;font-size:16px;font-weight:700;color:var(--ink)}
.lp-mini p{margin-block-start:8px;font-size:14px;line-height:1.55;color:var(--body)}
.lp-mini a,.lp-trust a{display:inline-flex;align-items:center;min-height:44px;font-size:14px;font-weight:700;color:var(--brand-text);
  text-decoration:underline;text-underline-offset:3px}
.lp-mini a:hover,.lp-trust a:hover{color:var(--ink)}
.lp-soon{margin-block-start:20px;padding:18px 20px;border-radius:var(--radius-card);border:1px dashed var(--line-strong);background:var(--surface)}
.lp-soon h3{font-size:14.5px;font-weight:700;color:var(--ink)}
.lp-soon ul{margin:8px 0 0;padding-inline-start:20px;display:flex;flex-direction:column;gap:4px}
.lp-soon li{font-size:14px;color:var(--body);line-height:1.5}

.lp-ev{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));gap:16px}
.lp-ev .card-h h3{font-size:15.5px;font-weight:700;color:var(--ink)}
.lp-steps{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.lp-steps li{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);padding:22px}
.lp-steps b{display:block;margin-block-start:14px;font-size:16.5px;color:var(--ink)}
.lp-steps p{margin-block-start:6px;font-size:14.5px;line-height:1.55;color:var(--body)}
.lp-trust{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.lp-trust > div{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);padding:22px}
.lp-trust h3{margin-block-start:12px;font-size:16px;font-weight:700;color:var(--ink)}
.lp-trust p{margin-block-start:8px;font-size:14.5px;line-height:1.55;color:var(--body)}

/* Edge to edge of the window, square, and closed off by a gold rule so the page has a colour break before the footer. */
.lp-final{margin-block-start:64px;margin-inline:calc(50% - 50vw);padding:56px 32px;border-radius:0;background:var(--hero);
  border-block-end:6px solid var(--brand-2);color:rgba(255,255,255,.80);text-align:center}
.lp-final h2{font-size:clamp(22px,3vw,32px);font-weight:700;color:#fff}
.lp-final > p{margin:10px auto 0;max-width:52ch;font-size:16px;line-height:1.6;color:rgba(255,255,255,.80)}
.lp-final .lp-cta{justify-content:center}
.lp-final .lp-contact{margin-block-start:18px;font-size:14px;color:rgba(255,255,255,.74)}
.lp-final .lp-contact a{color:#fff;font-weight:700;display:inline-block;padding-block:12px}
.lp-final .lp-contact a:hover{color:var(--accent)}

@media (max-width:1100px){
  .lp-flow{grid-template-columns:repeat(2,minmax(0,1fr))}
  .lp-mod-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:900px){
  .pub-head .lp-hero{grid-template-columns:1fr;gap:24px;padding-block:8px 36px}
  .stage-box,.stage-cap,.stage .dots{margin-inline:auto}
  .slide,.lp-intl,.lp-mod,.lp-share{grid-template-columns:1fr;gap:20px}
  .slide,.lp-intl{padding:20px}
  .lp-mod-rev .lp-mod-tx{order:0}
  .lp-steps,.lp-trust{grid-template-columns:1fr 1fr}
}
@media (max-width:600px){
  .lp-steps,.lp-trust,.lp-mod-grid,.lp-flow,.lp-flow-pics{grid-template-columns:1fr}
  .lp-sec{padding-block:40px 4px}
  .lp-cta > a{flex:1 1 100%}
  .stage-box{aspect-ratio:1/1.5}
  .stage .scene{grid-template-columns:1fr;grid-template-rows:auto auto auto;align-content:start}
  .stage .sc-photo{grid-column:1;grid-row:1;aspect-ratio:3/2;align-self:start}
  .stage .sc-card{grid-column:1;grid-row:2;align-self:start}
  .stage .sc-chip{grid-column:1;grid-row:3}
  .stage-cap{min-height:132px}
  .slides .tabs{flex-wrap:nowrap;overflow-x:auto;padding-block-end:4px}
  .slides .tab{flex:none}
  .slide h3{font-size:21px}
  .ncard{width:320px;gap:12px;padding:14px}
  .ncard .nph{width:88px}
  .ncard .nph img,.ncard .nph .lp-ph{width:88px;height:88px}
  .share-cards{gap:8px}
  .phone-card:nth-child(2){transform:none}
  .phone-card figcaption{font-size:11px}
  .lp-final{padding:32px 20px;margin-block-start:44px}
}
@media (prefers-reduced-motion:reduce){
  .stage .burst,.stage .sc-card .in,.stage .sc-chip .in{animation:none}
  .stage .el{transition:none}
  .marquee .track{animation:none;width:auto}
  .marquee{overflow-x:auto;-webkit-mask-image:none;mask-image:none}
  .ncard[aria-hidden="true"]{display:none}
}


/* ==========================================================================
   Phone tidy-up — the approved plan (artifact "Rapikan versi ponsel").
   Only layout on a narrow screen; the words, colours and the desktop page do
   not change. Selectors on the navy ground name .pub-bar or .pub-hero so
   tests/contrast.php measures them against it.
   ========================================================================== */
.pm-ico{display:none}
.pm-group > summary{list-style:none;display:flex;align-items:center;justify-content:space-between;min-height:44px;
  padding:8px 10px;border-radius:12px;font-weight:700;font-size:15px;color:var(--ink);cursor:pointer}
.pm-group > summary::-webkit-details-marker{display:none}
.pm-group > summary::marker{content:""}
.pm-group > summary:hover{background:var(--brand-tint-2);color:var(--ink)}
.pm-group .car{display:inline-flex;transition:transform .12s}
.pm-group[open] .car{transform:rotate(180deg)}
.lp-news-sec{padding-block:26px 8px}
.lp-prog{height:3px;border-radius:2px;background:var(--line);overflow:hidden}
.lp-prog i{display:block;height:100%;width:0;background:var(--brand-2)}
.lp-prog i.run{animation:lpProg var(--dur,4s) linear forwards}
@keyframes lpProg{to{width:100%}}
.news-nd{display:flex;gap:6px;justify-content:center;margin-block-start:8px}
.news-nd b{width:7px;height:7px;border-radius:50%;background:var(--line-strong)}
.news-nd b.on{background:var(--brand-2)}
.lp-open-prog{margin-block:-8px 12px}
@media (max-width:1040px){
  /* The "Create account" button in the menu was caught by the rule that hides the bar's app button. */
  .pub-bar .pm-acts .pub-app{display:inline-flex}
}
@media (max-width:600px){
  /* Header: one row — logo, language, menu button. */
  .pub-bar{gap:8px}
  .pub-bar .logo-link{position:relative;z-index:70}
  .pub-bar .langpick{order:2;margin-inline-start:auto;position:relative;z-index:70}
  .pub-bar .pubmenu{order:3;margin-inline-start:0}
  .pub-bar .pubmenu > summary{position:relative;z-index:70;width:44px;padding:0;justify-content:center}
  .pub-bar .pm-txt{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .pub-bar .pm-ico{display:block;width:18px;height:2px;border-radius:2px;background:currentColor;position:relative;
    box-shadow:0 -6px 0 currentColor,0 6px 0 currentColor;transition:transform .2s}
  .pub-bar .pm-ico::after{content:"";position:absolute;inset:0;border-radius:2px;background:currentColor;transform:rotate(90deg);opacity:0}
  .pub-bar .pubmenu[open] .pm-ico{transform:rotate(45deg);box-shadow:none}
  .pub-bar .pubmenu[open] .pm-ico::after{opacity:1}

  /* The menu: a full-screen navy sheet under the bar, groups as an accordion. */
  .pub-bar .pubmenu > .menupanel{position:fixed;inset:0;width:auto;max-height:none;border:0;border-radius:0;box-shadow:none;
    background:var(--hero) fixed;padding:84px 16px calc(16px + env(safe-area-inset-bottom));gap:0;overflow-y:auto;z-index:60}
  body:has(.pubmenu[open]){overflow:hidden}
  .pub-bar .pubmenu:not([open]) > .menupanel{display:none}
  .pub-bar .pm-group{border-block-end:1px solid rgba(255,255,255,.12)}
  .pub-bar .pm-group > summary{min-height:54px;padding:0 4px;font-size:17px;border-radius:0;color:#fff}
  .pub-bar .pm-group > summary:hover{background:transparent;color:#fff}
  .pub-bar .pm-group .car{color:var(--accent)}
  .pub-bar .pm-group .mg .mi{min-height:46px;padding:4px 4px 4px 2px;align-items:center;color:rgba(255,255,255,.9)}
  .pub-bar .pm-group .mg .mi:hover{background:rgba(255,255,255,.08);color:#fff}
  .pub-bar .pm-group .mg .mi b{font-size:14.5px;font-weight:600;color:#fff}
  .pub-bar .pm-group .mg .mi small{display:none}
  .pub-bar .pm-group .mg .mic{width:30px;height:30px;background:rgba(255,255,255,.10);color:#fff}
  .pub-bar .pubmenu-panel > .plain{min-height:54px;padding:0 4px;font-size:17px;border-radius:0;color:#fff;
    border-block-end:1px solid rgba(255,255,255,.12)}
  .pub-bar .pubmenu-panel > .plain:hover{background:transparent;color:var(--accent)}
  .pub-bar .pm-acts{flex-direction:column-reverse;align-items:stretch;gap:8px;margin-block-start:auto;padding-block:16px 0;
    border-block-start:0;position:sticky;inset-block-end:0;
    /* --hero is a gradient. Painted on this small strip it starts over from its own
       corner and shows as a differently coloured band behind the buttons. `fixed`
       pins both gradients to the viewport, so strip and sheet are one colour. */
    background:var(--hero) fixed}
  .pub-bar .pm-acts .pub-app{min-height:48px;font-size:15px;border-radius:999px}
  .pub-bar .pm-acts .plain{min-height:48px;justify-content:center;border:1px solid rgba(255,255,255,.45);border-radius:999px;
    color:#fff;font-size:15px}
  .pub-bar .pm-acts .plain:hover{background:rgba(255,255,255,.10);color:#fff}

  /* Hero: no "Open the app" text on a phone, the sports in one scrolling row each. */
  .lp-open{display:none}
  .pub-head .lp-hero .lp-sports ul{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;padding-block-end:2px}
  .pub-head .lp-hero .lp-sports ul::-webkit-scrollbar{display:none}
  .pub-head .lp-hero .lp-sports li{flex:none;white-space:nowrap}

  /* The stage: the photograph alone, its chip on it. The drawing is in the roles section anyway. */
  .stage-box{aspect-ratio:4/3;max-width:none}
  .stage .scene{display:block}
  .stage .sc-photo{position:absolute;inset:0;grid-column:auto;grid-row:auto;aspect-ratio:auto;align-self:auto}
  .stage .scene:not(.nophoto) .sc-card{display:none}
  .stage .sc-chip{position:absolute;inset-inline-end:10px;inset-block-end:10px;grid-column:auto;grid-row:auto}
  .stage-cap{min-height:116px;max-width:none}
  .stage .dots{max-width:none}

  /* One path as a compact numbered list. */
  .lp-flow-pics{grid-template-columns:1fr 1fr;gap:10px}
  .lp-flow{gap:0}
  .lp-flow li{flex-direction:row;align-items:flex-start;gap:12px;background:transparent;border:0;border-radius:0;
    border-block-end:1px solid var(--line);padding:12px 0}
  .lp-flow li:last-child{border-block-end:0}
  .lp-flow p{margin-block-start:2px;font-size:13.5px}

  /* News right under the roles, one card at a time, swiped or moved by the script. */
  .lp-main > .wrap{display:flex;flex-direction:column}
  .lp-main > .wrap > *{order:5}
  .lp-main > .wrap > #roles{order:1}
  .lp-main > .wrap > #news{order:2}
  .lp-main > .wrap > #flow{order:3}
  .lp-news-sec{padding-block:24px 0}
  .marquee{overflow-x:auto;scroll-snap-type:x mandatory;overscroll-behavior-x:contain;scrollbar-width:none;
    -webkit-mask-image:none;mask-image:none}
  .marquee::-webkit-scrollbar{display:none}
  .marquee .track{animation:none;width:auto;gap:12px}
  .ncard{flex:0 0 100%;width:100%;scroll-snap-align:start}
  .ncard[aria-hidden="true"]{display:none}

  /* The footer sitemap in two columns. */
  .sitemap{grid-template-columns:1fr 1fr;gap:4px 16px}
}

/* ------------------------------------------------ simulation & scouting --
   app/sim.php, sim_event.php, rivals.php, rival.php (inc/sim_ui.php draws
   the markup). Tokens only, like everything else below :root. */
.simbig{display:flex;gap:18px;align-items:center;flex-wrap:wrap;margin-bottom:6px}
.simbig .place{font-size:44px;font-weight:800;line-height:1;color:var(--brand-text)}
.simbig .place small{font-size:16px;font-weight:600;color:var(--muted)}
.stat.simon{border-color:var(--brand-2);box-shadow:inset 0 0 0 1px var(--brand-2)}
.simstrip{width:100%;height:auto;display:block;margin:10px 0 4px}
.simstrip .grid{stroke:var(--line);stroke-width:1}
.simstrip .lbl{fill:var(--muted);font-size:11px}
.simstrip .whisk{stroke:var(--muted);stroke-width:2}
.simstrip .box{fill:var(--brand-tint-2);stroke:var(--muted)}
.simstrip .med{stroke:var(--brand-text);stroke-width:2}
.simstrip .dot{fill:var(--muted)}
.simstrip .mk{stroke:var(--series-1);stroke-width:2}
.simstrip .you{fill:var(--brand-2);stroke:var(--brand-2-deep)}
.simstrip .youlbl{fill:var(--ink);font-size:12px;font-weight:700}
.simspark{display:block;max-width:100%;height:auto}
.simspark .area{fill:var(--brand-tint-2)}
.simspark .line{fill:none;stroke:var(--series-1);stroke-width:2}
.simspark .end{fill:var(--brand-2);stroke:var(--brand-2-deep)}
.simshare{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:12px}
.simshare .hint{flex-basis:100%}
.simh2h{display:flex;flex-direction:column;gap:9px;margin-bottom:10px}
.simh2h .legend{display:flex;gap:14px;flex-wrap:wrap;font-size:12px;color:var(--muted)}
.simh2h .legend i{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:5px;vertical-align:-1px}
.simh2h .legend i.a{background:var(--series-1)}
.simh2h .legend i.t{background:var(--brand-2)}
.simh2h .rn{display:grid;grid-template-columns:52px 1fr 52px;gap:8px;align-items:center;font-size:12px}
.simh2h .rn b{color:var(--muted)}
.simh2h .bars{display:flex;flex-direction:column;gap:3px;min-width:0}
.simh2h .vals{text-align:right;color:var(--ink)}
.simbar{display:flex;height:10px;border-radius:3px;overflow:hidden;background:var(--surface)}
.simbar .a{background:var(--series-1)}
.simbar .t{background:var(--brand-2)}
.simbar.me{opacity:.62}
.simbar .none{font-size:10px;line-height:10px;padding-left:4px;color:var(--muted)}
.t tr.simme td{background:var(--brand-2-soft);color:var(--ink)}
.t tr.simvs td{background:var(--brand-tint-2);color:var(--ink)}
.simzones{display:flex;flex-direction:column;gap:6px}
.simzones .z{display:grid;grid-template-columns:64px 1fr 52px;gap:8px;align-items:center;font-size:13px;color:var(--ink)}
.simzones .track{height:12px;background:var(--surface);border-radius:3px;overflow:hidden}
.simzones .fill{height:100%;background:var(--series-1)}
.simzones .fill.top{background:var(--brand-2)}

/* ---- Certified Trainer: four linked pickers (app/roles.php, app/grade_lookup.php).
   Same combobox as competition.css, which this page does not load. ---- */
.certpick{display:flex;flex-direction:column;gap:12px}
.certpick-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));gap:12px}
.certpick-grid[hidden],.certpick-plain[hidden],.certpick[hidden],#grade-free[hidden]{display:none}
.cbx{position:relative}
.cbx .cb-list{position:absolute;inset-inline:0;top:calc(100% + 4px);z-index:40;margin:0;padding:4px;list-style:none;background:var(--card);border:1px solid var(--line-strong);border-radius:10px;box-shadow:var(--shadow);max-height:280px;overflow:auto}
.cbx .cb-list li{padding:8px 11px;border-radius:7px;cursor:pointer;display:flex;flex-direction:column;gap:1px;color:var(--ink)}
.cbx .cb-list li[aria-selected="true"],.cbx .cb-list li:hover{background:var(--brand-tint-2);color:var(--ink)}
.cbx .cb-list li b{color:var(--ink);font-size:13.5px;font-weight:700}
.cbx .cb-list li small{color:var(--muted);font-size:12px;line-height:1.35}
.cbx .cb-list mark{background:var(--brand-2-soft);color:var(--ink);border-radius:3px;padding:0 1px}
.cbx .cb-none{padding:10px 11px;font-size:13px;color:var(--muted);cursor:default}

/* ---- Federation trainer grades (app/fed_grades.php) ---- */
.fg-row{display:flex;align-items:center;gap:10px;padding:10px 0;border-block-end:1px solid var(--line);flex-wrap:wrap}
.fg-row:last-child{border-block-end:0}
.fg-row .fg-n{flex:none;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;background:var(--brand-tint-2);color:var(--brand-text);font-size:12.5px;font-weight:700}
.fg-row .fg-name{flex:1 1 200px;min-width:0;color:var(--ink)}
.fg-row .fg-name small{display:block;color:var(--muted);font-size:12px}
.fg-row.off .fg-name{color:var(--muted)}
.fg-acts{display:flex;gap:6px;flex-wrap:wrap}

/* radar:start - News Radar (app/news_radar.php, app/news_sources.php). Tokens only, no colour literals. */
.radar-run{display:flex;flex-wrap:wrap;gap:14px 24px;align-items:center;justify-content:space-between}
.radar-runtext{display:flex;flex-wrap:wrap;gap:6px 20px;font-size:14px;color:var(--muted);min-width:0}
.radar-runtext b{color:var(--ink);font-variant-numeric:tabular-nums}
.radar-bar{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;justify-content:space-between;margin-block:16px 10px}
.radar-tabs{display:inline-flex;border:1px solid var(--line-strong);border-radius:8px;overflow:hidden;background:var(--card)}
.radar-tab{padding:7px 16px;font-size:14px;font-weight:600;color:var(--body);text-decoration:none;border-inline-end:1px solid var(--line)}
.radar-tab:last-child{border-inline-end:0}
.radar-tab:hover{background:var(--surface-hover);color:var(--ink)}
.radar-tab.on{background:var(--brand-tint-2);color:var(--brand-text);box-shadow:inset 0 -3px 0 var(--brand-2)}
.radar-chips{display:flex;flex-wrap:wrap;gap:8px;margin-block-end:16px}
.radar-chip{display:inline-flex;gap:6px;align-items:center;padding:5px 13px;border:1px solid var(--line-strong);border-radius:999px;background:var(--card);color:var(--body);font-size:13.5px;font-weight:600;text-decoration:none}
.radar-chip span{color:var(--muted);font-variant-numeric:tabular-nums;font-weight:400}
.radar-chip:hover{background:var(--surface-hover);color:var(--ink)}
.radar-chip:hover span{color:var(--body)}
.radar-chip.on{background:var(--brand-tint-2);border-color:var(--brand-2);color:var(--brand-text)}
.radar-chip.on span{color:var(--brand-text)}
.radar-feed{display:flex;flex-direction:column;gap:12px;margin-block-end:18px}
.radar-card{display:grid;grid-template-columns:176px minmax(0,1fr);gap:16px;padding:14px;border:1px solid var(--line);border-radius:10px;background:var(--card)}
.radar-img{display:block;aspect-ratio:4/3;border-radius:8px;overflow:hidden;background:var(--surface-hover);align-self:start}
.radar-img img{display:block;width:100%;height:100%;object-fit:cover}
.radar-card.noimg{grid-template-columns:minmax(0,1fr)}
.radar-card.noimg .radar-img{display:none}
.radar-body{min-width:0}
.radar-meta{display:flex;flex-wrap:wrap;gap:6px 12px;align-items:center;font-size:12.5px;color:var(--muted)}
.radar-score{display:inline-flex;gap:6px;align-items:center;font-variant-numeric:tabular-nums}
.radar-score i{display:block;width:48px;height:5px;border-radius:3px;background:var(--line);overflow:hidden}
.radar-score i b{display:block;height:100%;background:var(--ok)}
.radar-card h4{margin:6px 0;font-size:17px;line-height:1.3;text-wrap:balance}
.radar-card h4 a{color:var(--ink);text-decoration:none}
.radar-card h4 a:hover{text-decoration:underline}
.radar-sum{margin:0 0 6px;font-size:14px;color:var(--body);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.radar-also{margin:0 0 6px;font-size:13px;color:var(--muted)}
.radar-acts{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-block-start:8px}
.radar-acts form{display:inline-flex;gap:8px}
.radar-dropped{margin-block-start:8px}
.radar-dropped > summary{cursor:pointer}
.radar-droplist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.radar-droplist li{display:flex;gap:12px;align-items:center;justify-content:space-between;padding-block-start:10px;border-block-start:1px solid var(--line);font-size:14px}
.radar-droplist li:first-child{border-block-start:0;padding-block-start:0}
.radar-droplist li > div{min-width:0;display:flex;flex-direction:column;gap:2px}
.radar-droplist a{overflow-wrap:anywhere}
tr.radar-off td{opacity:.62}
.radar-rowacts{white-space:nowrap}
.radar-rowacts form{display:inline-flex;gap:6px;flex-wrap:nowrap;justify-content:flex-end}
.radar-del{margin-block-start:6px;font-size:13px}
.radar-del summary{cursor:pointer;color:var(--muted)}
.radar-formrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px}
.radar-topic{border-block-start:1px solid var(--line);padding-block:10px}
.radar-topic > summary{cursor:pointer;display:flex;gap:10px;align-items:baseline;flex-wrap:wrap}
.radar-topicform{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-block-start:10px}
.radar-topicform textarea{width:100%}
@media (max-width:640px){
  .radar-card{grid-template-columns:1fr}
  .radar-img{aspect-ratio:16/9}
  .radar-droplist li{flex-direction:column;align-items:flex-start}
}
/* develop screen (app/news_develop.php) */
.radar-new{margin-block-end:14px}
.radar-new > summary{cursor:pointer}
.dev-steps{display:flex;flex-wrap:wrap;gap:8px;margin-block-end:14px}
.dev-steps a{display:inline-flex;gap:6px;align-items:center;padding:5px 13px;border:1px solid var(--line-strong);border-radius:999px;background:var(--card);color:var(--body);font-size:13.5px;font-weight:600;text-decoration:none}
.dev-steps a b{display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--brand-tint-2);color:var(--brand-text);font-size:12px}
.dev-steps a:hover{background:var(--surface-hover);color:var(--ink)}
.dev-stack{display:flex;flex-direction:column;gap:14px;max-width:52rem}
.form.dev-inline{flex-direction:row;flex-wrap:wrap;align-items:flex-end;gap:12px}
.form.dev-inline > label{flex:1 1 220px}
.dev-two{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px}
.dev-three{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px}
.dev-acts{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.dev-chosen{display:flex;flex-wrap:wrap;gap:14px;align-items:flex-start}
.dev-chosen img,.dev-ref img{display:block;width:160px;max-width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:8px;background:var(--surface-hover)}
.dev-kinds{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:8px}
.dev-kind{display:flex;gap:10px;align-items:center;padding:9px 12px;border:1px solid var(--line-strong);border-radius:8px;background:var(--card);color:var(--body);font-size:14px;text-decoration:none}
.dev-kind b{display:inline-grid;place-items:center;flex:none;width:24px;height:24px;border-radius:50%;background:var(--brand-tint-2);color:var(--brand-text);font-size:12.5px}
.dev-kind span{flex:1;min-width:0}
.dev-kind:hover{background:var(--surface-hover);color:var(--ink)}
.dev-kind.on{background:var(--brand-tint-2);border-color:var(--brand-2);color:var(--brand-text);font-weight:600}
.dev-ref{display:flex;flex-wrap:wrap;gap:14px;align-items:flex-start;padding:12px;border:1px solid var(--line);border-radius:10px;background:var(--surface)}
.dev-refforms{display:flex;flex-wrap:wrap;gap:14px;flex:1 1 320px}
.dev-refforms .form{flex:1 1 240px}
.dev-kindform{padding:14px;border:1px solid var(--line-strong);border-radius:10px;background:var(--card)}
.dev-ba{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.dev-ba figure{margin:0}
.dev-ba img{display:block;width:100%;border-radius:8px}
.dev-ba figcaption{font-size:12.5px;color:var(--muted);margin-block-start:4px}
.dev-rights{padding:10px 12px;border-radius:8px;background:var(--warn-bg)}
@media (max-width:640px){
  }
/* radar:end */

/* news:start - the public news pages (public/news.php, public/news_item.php), the home page's news block and the comment
   list an administrator works from. Tokens only, no colour literal. */
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.nw{display:flex;flex-direction:column;gap:18px;min-width:0}
.nw-pill{display:inline-flex;align-items:center;gap:7px;min-height:44px;padding-inline:16px;border:1px solid var(--line-strong);border-radius:var(--radius-pill);background:var(--card);color:var(--ink);font-weight:600;font-size:13.5px}
.nw-pill:hover{background:var(--surface-hover);color:var(--ink)}
.nw-search{display:flex;gap:8px}
.nw-search input{flex:1;min-width:0;min-height:44px;padding:10px 14px;border:1px solid var(--line-strong);border-radius:var(--radius-field);background:var(--card);color:var(--ink);font:inherit}
.nw-search input::placeholder{color:var(--muted)}
.nw-tabs{display:flex;gap:2px;flex-wrap:wrap;border-block-end:1px solid var(--line)}
.nw-tab{display:inline-flex;align-items:center;gap:6px;min-height:44px;padding-inline:12px;color:var(--muted);font-weight:700;font-size:14px;border-block-end:3px solid transparent;margin-block-end:-1px;white-space:nowrap}
.nw-tab small{font-weight:600;font-size:12px;font-variant-numeric:tabular-nums}
.nw-tab:hover{color:var(--ink)}
.nw-tab[aria-current="page"]{color:var(--ink);border-block-end-color:var(--brand-2)}
.nw-tab.zero{opacity:.6}
.nw-statebar{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.nw-state{margin:0;color:var(--muted);font-size:13.5px}
.nw-state b{color:var(--ink)}
.nw-cols{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:28px;align-items:start}
.nw-main{display:flex;flex-direction:column;gap:24px;min-width:0}
.nw-aside{display:flex;flex-direction:column;gap:20px;min-width:0}
.nw-sech{margin:0;padding-block-end:8px;font-size:12px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);font-weight:700}
.nw-top5{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);gap:20px}
.nw-sidelist{display:flex;flex-direction:column;min-width:0}
.nw-th{position:relative;display:block;overflow:hidden;min-width:0;aspect-ratio:16/10;border-radius:8px;background:var(--brand-tint-2)}
.nw-th img{display:block;width:100%;height:100%;object-fit:cover}
.nw-th.nw-wide{border-radius:10px}
.nw-cnt{position:absolute;inset-inline-end:8px;inset-block-end:8px;padding:2px 8px;border-radius:999px;background:var(--viewer-bg);color:var(--viewer-ink);font-size:11.5px;font-weight:700}
.nw-badge{position:absolute;inset-inline-start:12px;inset-block-start:12px;z-index:2;padding:3px 9px;border-radius:6px;background:var(--brand-2);color:var(--on-brand-2);font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase}
.nw-lp{position:relative;display:block}
.nw-lead{display:flex;flex-direction:column;gap:10px;min-width:0;color:inherit}
.nw-row{display:grid;grid-template-columns:128px minmax(0,1fr);gap:14px;align-items:start;padding-block:14px;border-block-start:1px solid var(--line);color:inherit}
.nw-feed .nw-row:first-child,.nw-sidelist .nw-row:first-child{border-block-start:0;padding-block-start:0}
.nw-sidelist .nw-row,.nh-list .nw-row{grid-template-columns:92px minmax(0,1fr)}
.nw-sidelist .nw-th,.nh-list .nw-th{aspect-ratio:1}
.nw-sidelist .nw-cnt,.nh-list .nw-cnt{display:none}
.nw-rx{display:flex;flex-direction:column;gap:5px;min-width:0}
.nw-ti{font-size:18px;font-weight:700;color:var(--ink);line-height:1.25;overflow-wrap:anywhere}
.nw-sidelist .nw-ti,.nh-list .nw-ti{font-size:16.5px}
.nw-ti.nw-big{font-size:26px;line-height:1.2}
.nw-su{font-size:14px;color:var(--body);overflow-wrap:anywhere;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.nw-lead .nw-su{-webkit-line-clamp:3}
.nw-row:hover .nw-ti,.nw-lead:hover .nw-ti,.nw-pop a:hover .nw-ti{text-decoration:underline;text-decoration-color:var(--brand-2);text-decoration-thickness:2px;text-underline-offset:3px}
.nw-meta{display:flex;flex-wrap:wrap;gap:4px 10px;align-items:center;font-size:12.5px;color:var(--muted)}
.nw-kick{font-size:12px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--brand-2-deep)}
.nw-st{display:inline-flex;gap:4px;align-items:center}
.nw-i{flex:none}
.nw-box{padding:14px 16px;border:1px solid var(--line);border-radius:12px;background:var(--card)}
.nw-box h2{margin-block-end:6px;font-size:19px}
.nw-pop{list-style:none;margin:0;padding:0;counter-reset:p}
.nw-pop li{display:grid;grid-template-columns:28px minmax(0,1fr);gap:8px;padding-block:10px;border-block-start:1px solid var(--line);counter-increment:p}
.nw-pop li:first-child{border-block-start:0}
.nw-pop li::before{content:counter(p);font-weight:700;font-size:22px;line-height:1;color:var(--brand-2-deep)}
.nw-pop a{display:flex;flex-direction:column;gap:3px;min-width:0;color:inherit}
.nw-pop .nw-ti{font-size:16px}
.nw-empty{display:flex;flex-direction:column;gap:8px;align-items:center;padding:32px 20px;text-align:center;border:1px dashed var(--line-strong);border-radius:12px;background:var(--card)}
.nw-empty b{font-size:19px;color:var(--ink)}
.nw-pager{display:flex;flex-wrap:wrap;gap:6px;justify-content:center;align-items:center}
.nw-pager a{display:inline-grid;place-items:center;min-width:44px;min-height:44px;border:1px solid var(--line-strong);border-radius:10px;background:var(--card);color:var(--ink);font-weight:600}
.nw-pager a[aria-current="page"]{background:var(--brand);border-color:var(--brand);color:#fff}
.nw-gap{color:var(--muted)}
/* the home page's block */
.nh-box{padding:20px;border:1px solid var(--line);border-radius:var(--radius-card);background:var(--card)}
.nh-h{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-block-end:16px}
.nh-h h3{font-size:24px}
.nh-grid{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);gap:24px}
.nh-list{display:flex;flex-direction:column;min-width:0}
/* one story */
.na{display:flex;flex-direction:column;gap:16px;max-width:780px;margin-inline:auto;min-width:0}
.na-crumb{font-size:13px;color:var(--muted)}
.na-crumb a{font-weight:600}
.na-head{display:flex;flex-direction:column;gap:10px;align-items:center;text-align:center;padding-block-start:6px}
.na-head h1{font-size:clamp(28px,5vw,40px);line-height:1.12;overflow-wrap:anywhere}
.na-by{margin:0;font-size:14px;font-weight:600;color:var(--ink)}
.na-by span{color:var(--brand-2-deep)}
.na-dt,.na-note{margin:0;font-size:13px;color:var(--muted)}
.na-acts{position:relative;display:flex;align-items:center;gap:4px;padding-block:4px;border-block:1px solid var(--line)}
.na-f{display:contents}
.na-act{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:44px;min-height:44px;padding-inline:10px;border:0;border-radius:10px;background:transparent;color:var(--muted);font:inherit;font-weight:700;font-size:14px;cursor:pointer}
.na-act:hover{background:var(--brand-tint-2);color:var(--ink)}
.na-act[aria-pressed="true"]{background:var(--brand-tint-2);color:var(--brand-text)}
.na-act[aria-pressed="true"] svg{fill:currentColor}
.na-sp{margin-inline-start:auto}
.na-share{position:relative}
.na-share > summary{list-style:none}
.na-share > summary::-webkit-details-marker{display:none}
.na-pop{position:absolute;inset-inline-end:0;inset-block-start:calc(100% + 6px);z-index:30;display:flex;gap:2px;padding:5px;border:1px solid var(--line-strong);border-radius:12px;background:var(--card);box-shadow:var(--shadow)}
.na-pop a,.na-pop button{display:grid;place-items:center;width:44px;height:44px;border:0;border-radius:10px;background:transparent;color:var(--ink);cursor:pointer}
.na-pop a:hover,.na-pop button:hover{background:var(--brand-tint-2);color:var(--ink)}
.na-pop button[hidden]{display:none}
.na-toast{position:fixed;inset-inline:16px;inset-block-end:calc(20px + env(safe-area-inset-bottom,0px));z-index:70;width:max-content;max-width:calc(100% - 32px);margin-inline:auto;padding:9px 16px;border-radius:999px;background:var(--ink);color:var(--card);font-size:13.5px;font-weight:600;box-shadow:var(--shadow)}
.na-toast[hidden]{display:none}
.na-lede{margin:0;font-size:18px;font-weight:600;color:var(--ink)}
.na-car{position:relative;overflow:hidden;border:1px solid var(--line);border-radius:10px;background:var(--card)}
.na-slide{margin:0}
.na-slide img{display:block;width:100%;height:auto}
.na-slide figcaption{padding:10px 14px 12px;font-size:14px;color:var(--body)}
.na-car.js .na-slide{display:none}
.na-car.js .na-slide.on{display:block}
.na-car.js .na-slide img{aspect-ratio:16/10;object-fit:contain;background:var(--surface);cursor:zoom-in}
.na-bar{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 6px 6px 14px}
.na-cc{font-size:13px;font-weight:700;color:var(--muted);font-variant-numeric:tabular-nums}
.na-zoom{display:grid;place-items:center;width:44px;height:44px;border:1px solid var(--line-strong);border-radius:10px;background:var(--card);color:var(--ink);cursor:pointer}
.na-zoom:hover{background:var(--brand-tint-2);color:var(--ink)}
.na-nv{position:absolute;z-index:3;display:grid;place-items:center;width:44px;height:44px;border:0;background:var(--viewer-bg);color:var(--viewer-ink);cursor:pointer}
.na-nv{inset-block-start:36%;translate:0 -50%;border-radius:50%}
.na-pv{inset-inline-start:10px}
.na-nx{inset-inline-end:10px}
.na-body{font-size:16.5px;line-height:1.7;overflow-wrap:anywhere}
.na-body p{margin:0 0 16px}
.na-body img{max-width:100%;height:auto}
.na-tags{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:0}
.na-tags span{font-size:13px;color:var(--muted)}
.na-tags a{display:inline-flex;align-items:center;min-height:44px;padding-inline:14px;border:1px solid var(--line-strong);border-radius:999px;background:var(--card);color:var(--ink);font-weight:600;font-size:13.5px}
.na-sec{display:flex;flex-direction:column;gap:10px}
.na-sec > h2{font-size:24px}
.na-cmt{padding:16px;border:1px solid var(--line);border-radius:12px;background:var(--card)}
.na-cf{display:flex;flex-direction:column;gap:8px}
.na-cf textarea{width:100%;min-height:92px;resize:vertical;padding:10px 12px;border:1px solid var(--line-strong);border-radius:var(--radius-field);background:var(--card);color:var(--ink);font:inherit}
.na-cr{display:flex;justify-content:space-between;gap:10px;align-items:center;flex-wrap:wrap}
.na-guest{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap;padding:12px 14px;border:1px dashed var(--line-strong);border-radius:10px;background:var(--surface)}
.na-cl{list-style:none;margin:14px 0 0;padding:0}
.na-cl li{display:grid;grid-template-columns:36px minmax(0,1fr);gap:12px;padding-block:14px;border-block-start:1px solid var(--line)}
.na-av{display:grid;place-items:center;width:36px;height:36px;border-radius:50%;background:var(--brand-tint-2);color:var(--brand-text);font-weight:700;font-size:14px}
.na-who{display:flex;flex-wrap:wrap;gap:4px 8px;align-items:center;margin:0;font-weight:700;font-size:14px;color:var(--ink)}
.na-who small{font-weight:400;font-size:12.5px;color:var(--muted)}
.na-ct{margin:2px 0 0;overflow-wrap:anywhere}
.na-ax{display:flex;gap:4px;margin-block-start:2px}
.na-ax form{display:inline}
.na-ax button{display:inline-flex;gap:4px;align-items:center;min-height:44px;padding-inline:10px;border:0;border-radius:8px;background:transparent;color:var(--muted);font:inherit;font-size:13px;font-weight:600;cursor:pointer}
.na-ax button:hover{background:var(--brand-tint-2);color:var(--ink)}
/* the full-screen photograph */
.nw-viewer{position:fixed;inset:0;z-index:60;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:calc(20px + env(safe-area-inset-top,0px)) 16px calc(20px + env(safe-area-inset-bottom,0px));background:var(--viewer-bg);color:var(--viewer-ink)}
.nw-viewer[hidden]{display:none}
.nw-viewer figure{display:flex;flex-direction:column;gap:10px;align-items:center;width:min(1000px,100%);margin:0}
.nw-viewer img{max-width:100%;max-height:72vh;object-fit:contain;border-radius:8px}
.nw-viewer figcaption{font-size:15px;text-align:center}
.nw-vc{margin:0;font-size:13px;font-variant-numeric:tabular-nums}
.nw-viewer button{display:grid;place-items:center;width:44px;height:44px;border:0;border-radius:50%;background:var(--ink);color:var(--viewer-ink);box-shadow:inset 0 0 0 1px var(--viewer-ink);font-size:24px;line-height:1;cursor:pointer}
.nw-vx{position:absolute;inset-inline-end:16px;inset-block-start:calc(16px + env(safe-area-inset-top,0px))}
.nw-vn{position:absolute;inset-block-start:50%;translate:0 -50%}
.nw-vp{inset-inline-start:12px}
.nw-vq{inset-inline-end:12px}
body.nw-lock{overflow:hidden}
/* the administrator's list of comments */
.nf-dates{display:flex;flex-wrap:wrap;gap:2px 14px;margin-block-start:2px;font-variant-numeric:tabular-nums}
.nf-dates span{white-space:nowrap}
.nf-table td:first-child{min-width:11rem;overflow-wrap:anywhere}
.nf-table .nf-reads{white-space:nowrap}
.nf .dev-acts{margin-block-start:10px}
.nc-list{display:flex;flex-direction:column;gap:12px}
.nc-head{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap}
.nc-pills{display:flex;gap:6px;flex-wrap:wrap;align-items:flex-start}
.nc-body{margin:10px 0;overflow-wrap:anywhere}
.nc-acts{display:flex;gap:8px;flex-wrap:wrap}
@media (max-width:980px){
  .nw-cols{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:860px){
  .nw-top5,.nh-grid{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:560px){
  .nh-box{padding:16px}
  .nw-row{grid-template-columns:104px minmax(0,1fr);gap:12px}
  .nw-ti{font-size:17px}
  .nw-ti.nw-big{font-size:23px}
  .nw-feed .nw-su{display:none}
  .nw-tabs{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin}
  .nw-tab{flex:none}
  .nw-viewer .nw-vn{width:40px;height:40px}
  .na-pop{inset-inline-end:-8px}
}
@media (max-width:1040px){
  .na-crumb a{display:inline-block;min-width:44px;text-align:center;padding-block:12px;margin-block:-12px}
  .na-head .nw-kick{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px}
}
@media (max-width:640px){
  /* a row of tabs wider than the screen is dragged sideways inside its own box, not pushed off the page */
  .radar-tabs{display:flex;max-width:100%;overflow-x:auto;scrollbar-width:thin}
  .radar-tab{flex:none;white-space:nowrap}
}
/* news:end */
/* mobile:start - what a 412px phone (Galaxy S20 FE) showed wrong: a squashed Sign in pill, a site name cut to one
   letter, titles behind "…", long words past a card's edge. Found by tools/mobile_audit.php; tokens only. */
.topbar > a.ttl,.topbar .btn,.topbar .langpick,.topbar .langsw,.topbar .navmenu{flex:none}
.topbar .btn{white-space:nowrap}
@media (max-width:820px){
  /* the site name is the one thing in the bar that must never shrink */
  .topbar > a.ttl{overflow:visible;text-overflow:clip;max-width:none}
  /* the page title takes what is left and runs to two lines rather than ending in "…" */
  .topbar > div:not(.sp):not(.me){flex:1 1 0;min-width:0}
  .topbar > div:not(.sp):not(.me) .ttl{white-space:normal;overflow:hidden;text-overflow:clip;line-height:1.15;
    display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}
}
@media (max-width:560px){
  /* on a public page the heading sits directly below the bar, so the bar keeps the name, Sign in and language */
  .topbar > a.ttl ~ div:not(.sp){display:none}
  .article .lede{font-size:17px}
  .article p{font-size:16.5px}
}
/* a long word, a link or a number must wrap inside its card instead of leaving it */
.content h1,.content h2,.content h3,.content h4,.content p,.content li,.newscard,.hint,.note{overflow-wrap:anywhere}
.content td,.content th{overflow-wrap:break-word}
.newscard,.newscard .tx,.card,.card-b{min-width:0}
/* thumbs: the targets the audit found under 44px, grown without moving the layout around them */
@media (max-width:1040px){
  /* the public site name is a link on its own */
  .topbar > a.ttl{display:inline-flex;align-items:center;min-height:44px}
  /* a bare link alone in a table cell or a list item: the box grows, the margin takes the growth back,
     so the row does not get taller but the target does. A classless anchor only; a styled one has its own rule. */
  .content td > a:only-child:not([class]),.content td > b > a:only-child:not([class]),.content li > a:only-child:not([class]),
  .ncard .nlink,.radar-droplist a{display:inline-block;min-width:44px;padding-block:12px;margin-block:-12px}
  /* the sport links in the home page's first panel */
  .pub-head .lp-hero .lp-sports li a{display:flex;align-items:center;min-height:44px}
  /* a disclosure heading is a target too (padding keeps the marker, which display:flex would remove) */
  .content details > summary{padding-block:12px}
  /* a button that looks like a chip, and the page-level .chip rules that came later than the floor above */
  html body .chip,html body button.chip,html body a.chip,html body .page-col .chip{min-height:44px}
  /* helper text under a field is a run of words, so it takes the 12px floor the label style (11.5px) sits just under */
  .form label > span,html body .hintx,html body .page-col .hintx,html body .page-col .form label > span{font-size:12px}
  .radar-tab,.radar-chip,.dev-steps a{min-height:44px;display:inline-flex;align-items:center}
  /* the text editor's toolbar */
  div.ql-toolbar.ql-snow button{min-width:44px;height:44px}
  div.ql-toolbar.ql-snow .ql-picker-label{min-height:44px;display:inline-flex;align-items:center}
  /* the account line under the name is a run of text, so it takes the 12px floor */
  .who .rl,.me .rl{font-size:12px}
  /* a table of sources: the buttons of a row wrap instead of pushing the table past the screen */
  .radar-rowacts{white-space:normal}
  .radar-rowacts form{flex-wrap:wrap}
  .radar-del summary{display:inline-block;padding-block:12px}
  /* the competition header's link to the list: an icon button that carries a word */
  header.ph .ib{min-width:44px;width:auto;padding-inline:10px;white-space:nowrap}
  /* a title that is a link, and the back link that stands on a line of its own */
  .rowlink,.radar-card h4 a{display:inline-block;min-width:44px;padding-block:12px;margin-block:-12px}
  .backlink{display:inline-flex;align-items:center;min-height:44px}
  .radar-del summary{min-width:44px}
}
@media (max-width:560px){
  /* a button with a long label wraps inside the screen instead of running past it */
  .content .btn{white-space:normal;text-align:center;max-width:100%}
}
/* small print that carries information (a translation notice, the share label, the footer line) reads as grey on grey in
   the lightest ink; it takes the readable muted ink instead */
.article .sub2,.sharebar .sub2,.foot,.foot .credit{color:var(--muted)}
/* mobile:end */
/* ==========================================================================
   Trainer and student — mobile first.

   Written for a 412px phone (a Galaxy S20 FE) and widened from there. Every
   control a thumb has to hit is at least 44px tall and never shares a row with
   another when the row is narrow: it stacks and goes full width instead. The
   page must never scroll sideways, and long names wrap rather than push.
   ========================================================================== */
.navbadge{
  font-style:normal;flex:none;margin-inline-start:auto;
  min-width:22px;height:22px;padding-inline:6px;border-radius:11px;
  background:var(--stop);color:#fff;font-size:12px;font-weight:800;line-height:22px;text-align:center;
  font-variant-numeric:tabular-nums;
}
.answer{display:grid;gap:10px;width:100%}
.answer .btn,.answer summary.btn{width:100%;min-height:44px;display:flex;align-items:center;justify-content:center;text-align:center;list-style:none}
.answer summary.btn::-webkit-details-marker{display:none}
.answer details.decline{display:grid;gap:14px}
.answer details.decline[open]{padding:12px;border:1px solid var(--line);border-radius:var(--radius-card);background:var(--surface)}
.answer details.decline label{display:grid;gap:6px}
.answer details.decline select{width:100%;min-height:44px;font-size:16px}
@media (min-width:640px){
  .answer{display:flex;flex-wrap:wrap;align-items:flex-start;width:auto}
  .answer .btn,.answer summary.btn{width:auto;min-width:120px}
  .answer details.decline[open]{flex-basis:100%}
}
.modrow>div{min-width:0;overflow-wrap:anywhere}
@media (max-width:639px){
  .modrow{flex-direction:column;align-items:stretch;gap:10px}
  .modrow form,.modrow .actions{width:100%}
}
/* The trainer finder on a phone: the list is as wide as the field and tall enough to tap. */
.cbx input[type="text"],.cbx input[type="search"]{min-height:44px;font-size:16px}
.cbx .cb-list li{min-height:44px;justify-content:center}
.askcard{border-color:var(--brand-2);background:var(--brand-2-soft)}
.askcard .card-b{display:grid;gap:8px}
.askcard .btn{min-height:44px;display:flex;align-items:center;justify-content:center}
@media (min-width:640px){.askcard .btn{display:inline-flex;justify-self:start}}
/* An application waiting for a decision: evidence first, then the controls, each full width on a phone. */
.reqform{display:grid;gap:12px;padding-block:14px;border-block-end:1px solid var(--line)}
.reqform:last-child{border-block-end:0}
.reqform>div{min-width:0;overflow-wrap:anywhere}
.reqform .evidence a{color:var(--brand-text);text-decoration:underline;word-break:break-all}
.reqform label{display:grid;gap:6px}
.reqform input,.reqform select{width:100%;min-height:44px;font-size:16px}
.reqform .btn{width:100%;min-height:44px;display:flex;align-items:center;justify-content:center}
@media (min-width:640px){
  .reqform{display:flex;flex-wrap:wrap;align-items:flex-end}
  .reqform>div{flex:1 1 100%}
  .reqform label{flex:1 1 200px}
  .reqform .btn{width:auto;min-width:120px}
}

/* ----- My athletes: the roster, filters and group view (mobile first) ----- */
.rbar{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-block-end:12px}
.rbar .rsearch{grid-column:1 / -1}
.rbar input[type="search"],.rbar select{width:100%;min-height:44px;font-size:16px}
.fbtn{display:none}
.roster-form.js .fbtn{display:inline-flex;align-items:center;justify-content:center;min-height:44px;width:100%}
.rchips{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-block-end:12px}
.rchips .chip{min-height:40px;display:inline-flex;align-items:center;text-decoration:none}
.rchips .more{min-height:40px;display:inline-flex;align-items:center}
.rlayout{display:grid;gap:16px}
.rmain{display:grid;gap:14px;min-width:0}

.fpanel{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);padding:12px 16px}
.fpanel .fhead{display:none}
.fgroup{border:0;margin:0 0 12px;padding:0 0 4px;min-width:0}
.fgroup legend{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);padding:0;margin-block-end:2px}
.fopt{display:flex;align-items:center;gap:12px;min-height:44px;cursor:pointer}
.fopt input{width:22px;height:22px;flex:none;margin:0}
.fopt .fl{min-width:0;overflow-wrap:anywhere}
.fopt .c{margin-inline-start:auto;color:var(--muted);font-variant-numeric:tabular-nums;font-size:13px}
.fmore summary{min-height:44px;display:flex;align-items:center;color:var(--brand-text);font-weight:600;cursor:pointer}
.ffoot{display:grid;gap:8px;padding-block:12px;position:sticky;bottom:0;background:var(--card)}
.ffoot .btn,.abar .btn{min-height:44px;display:flex;align-items:center;justify-content:center}
.fscrim{position:fixed;inset:0;background:rgba(1,27,47,.45);z-index:55}
.fpanel.sheet{position:fixed;inset-inline:0;bottom:0;max-height:88vh;max-height:88dvh;overflow:auto;z-index:60;
  border:0;border-radius:18px 18px 0 0;padding:16px 16px 0;box-shadow:0 -10px 30px rgba(1,27,47,.25)}
.fpanel.sheet .fhead{display:flex;align-items:center;justify-content:space-between;margin-block-end:6px}
.fpanel.sheet .fclose{min-height:44px;min-width:44px}
body.noscroll{overflow:hidden}

.kpis2{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-block-end:14px}
.kpi2{background:var(--surface);border-radius:12px;padding:10px 12px;min-width:0}
.kpi2 .l{font-size:12px;color:var(--muted);overflow-wrap:anywhere}
.kpi2 .v{font-size:24px;font-weight:800;color:var(--ink);line-height:1.2}
.kpi2 .d{font-size:12px;color:var(--muted)}
.gfeeds{display:grid;gap:16px}
.gfeeds h3{font-size:15px;margin:0 0 4px}
.frow{display:flex;justify-content:space-between;align-items:center;gap:10px;min-height:44px;padding-block:6px;
  border-bottom:1px dashed var(--line);text-decoration:none;color:var(--body)}
.frow>span:first-child{min-width:0;overflow-wrap:anywhere}
.frow .sub{flex:none}

.rlist{display:grid;gap:12px}
.rcard{display:grid;grid-template-columns:auto minmax(0,1fr);gap:6px 10px;background:var(--card);
  border:1px solid var(--line);border-radius:var(--radius-card);padding:12px}
.rpick{display:flex;align-items:flex-start;justify-content:center;min-width:44px;min-height:44px;cursor:pointer}
.rpick input{width:24px;height:24px;margin:8px 0 0}
.rbody{min-width:0}
.rname{overflow-wrap:anywhere}
.rchips2{display:flex;flex-wrap:wrap;gap:6px;margin-block:6px}
.rnote{font-size:13px;color:var(--body);overflow-wrap:anywhere}
.ropen{grid-column:1 / -1;min-height:44px;display:flex;align-items:center;justify-content:center}
.abar{position:sticky;bottom:0;z-index:5;display:grid;gap:8px;background:var(--card);
  border-top:1px solid var(--line);padding-block:10px}

@media (min-width:640px){
  .rbar{grid-template-columns:1fr 200px}
  .rbar .rsearch{grid-column:auto}
  .roster-form.js .fbtn{grid-column:1 / -1}
}
@media (min-width:900px){
  .rbar{grid-template-columns:1fr 220px}
  .roster-form.js .fbtn{display:none}
  .rlayout{grid-template-columns:260px minmax(0,1fr);align-items:start}
  .fpanel{position:sticky;top:12px;max-height:calc(100vh - 24px);overflow:auto}
  .gfeeds{grid-template-columns:1fr 1fr}
  .rlist{grid-template-columns:repeat(auto-fill,minmax(340px,1fr))}
  .abar{grid-template-columns:1fr auto;align-items:center}
}
.rbar input[type="search"],.rbar select{border:1px solid var(--line-strong);border-radius:var(--radius-field);padding:10px 12px;background:#fff;color:var(--ink);font-family:inherit}
.kpis2{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.kpi2{padding:8px 10px}
.kpi2 .l{font-size:11px;line-height:1.25;min-height:28px}
.kpi2 .v{font-size:20px}
.kpi2 .d{font-size:11px;line-height:1.25}
.gdetails>summary{min-height:44px;display:flex;align-items:center;font-weight:600;color:var(--brand-text);cursor:pointer}
.abar .sub{display:none}
@media (min-width:640px){.abar .sub{display:block}.kpi2 .v{font-size:24px}.kpi2 .l{font-size:12px}}

/* ----- One athlete, in tabs (mobile first) ----- */
.athead{display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px;align-items:center;margin-block-end:12px}
.avt{width:48px;height:48px;border-radius:50%;background:var(--brand-tint-2);color:var(--brand-text);display:grid;place-items:center;font-weight:800;font-size:17px}
.atinfo{min-width:0}
.atname{margin:0;font-size:20px;overflow-wrap:anywhere}
.atacts{grid-column:1 / -1;display:grid;gap:8px}
.atacts .btn{min-height:44px;display:flex;align-items:center;justify-content:center;text-align:center}
.atabs{display:flex;gap:4px;overflow-x:auto;border-block-end:1px solid var(--line);margin-block-end:14px;-webkit-overflow-scrolling:touch;scroll-snap-type:x proximity}
.atabs a{flex:none;min-height:44px;display:flex;align-items:center;padding-inline:14px;color:var(--muted);text-decoration:none;
  border-block-end:3px solid transparent;font-weight:600;white-space:nowrap;scroll-snap-align:start}
.atabs a[aria-current="page"]{color:var(--ink);border-color:var(--brand-2)}
.clist{display:grid}
.crow{display:flex;justify-content:space-between;gap:12px;align-items:center;padding-block:10px;border-block-end:1px dashed var(--line);min-height:44px}
.cwhat{min-width:0;overflow-wrap:anywhere}
.ctot{flex:none;font-weight:800;color:var(--ink);font-size:18px}
@media (min-width:640px){
  .athead{grid-template-columns:auto minmax(0,1fr) auto}
  .atacts{grid-column:auto;display:flex}
  .atacts .btn{min-width:150px}
}
.atabs{scrollbar-width:none}
.atabs::-webkit-scrollbar{display:none}
/* Five sections fit on a phone without sideways scrolling: they wrap into pills. */
.atabs{flex-wrap:wrap;overflow:visible;gap:8px;border-block-end:0;padding-block-end:4px}
.atabs a{flex:1 1 auto;justify-content:center;border:1px solid var(--line-strong);border-radius:var(--radius-pill);background:var(--card);padding-inline:14px}
.atabs a[aria-current="page"]{background:var(--brand-2);border-color:var(--brand-2);color:var(--on-brand-2)}

/* ----- Find an athlete (mobile first) ----- */
.finder{display:grid;gap:12px}
.finder .fld{display:grid;gap:6px}
.finder .fld span{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.finder input,.finder select{width:100%;min-height:44px;font-size:16px;border:1px solid var(--line-strong);border-radius:var(--radius-field);padding:10px 12px;background:#fff;color:var(--ink);font-family:inherit}
.finder .btn{min-height:44px;display:flex;align-items:center;justify-content:center}
.fcard{grid-template-columns:minmax(0,1fr)}
.fcard .fform .btn{width:100%;min-height:44px;display:flex;align-items:center;justify-content:center}
.pager{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-block-start:14px}
.pager .btn{min-height:44px;display:flex;align-items:center}
@media (min-width:640px){
  .finder{grid-template-columns:repeat(2,minmax(0,1fr))}
  .finder .btn{grid-column:1 / -1;justify-self:start;min-width:140px}
  .fcard{grid-template-columns:minmax(0,1fr) auto;align-items:center}
  .fcard .fform .btn{width:auto;min-width:120px}
}
.btn.wide{width:100%;min-height:44px;display:flex;align-items:center;justify-content:center}
@media (min-width:640px){.btn.wide{width:auto;min-width:160px}}
.finder{margin-block-start:14px}
.btn.wide{margin-block-start:10px}
.answer details.decline select{font-family:inherit;border:1px solid var(--line-strong);border-radius:var(--radius-field);padding:10px 12px;background:#fff;color:var(--ink)}
.reqform select,.reqform input{font-family:inherit}
.rsort{display:block;min-width:0}
.ggroup{min-width:0}
.fform{display:block}
.evidence{min-width:0}

/* ----- The module builder: one page, one save (mobile first) ----- */
.mb .mform{display:grid;gap:12px}
.mb .fld{display:grid;gap:6px;min-width:0}
.mb .fld>span{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.mb input[type="text"],.mb select,.mb textarea{width:100%;min-height:44px;font-size:16px;font-family:inherit;color:var(--ink);
  border:1px solid var(--line-strong);border-radius:var(--radius-field);padding:10px 12px;background:#fff}
.mb input[readonly]{background:var(--surface);color:var(--muted)}
.mbgrid{display:grid;gap:14px}
.mrow{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;padding-block:12px;border-block-end:1px dashed var(--line)}
.mb.js .blank{display:none}
.mrow .mname,.mrow .mguide,.mrow .mdrop,.mrow .mlock{grid-column:1 / -1}
.mguide summary{min-height:44px;display:flex;align-items:center;cursor:pointer;color:var(--brand-text);font-weight:600}
.mdrop{display:flex;align-items:center;gap:10px;min-height:44px;cursor:pointer}
.mdrop input{width:22px;height:22px;flex:none;margin:0}
.mgroup{border:1px solid var(--line);border-radius:var(--radius-card);padding:0 12px 12px;margin-block:14px;background:var(--surface)}
.mgroup .mrow{padding-inline-start:10px;border-inline-start:3px solid var(--line-strong);margin-block-start:6px;background:var(--card)}
.mgroup-h{display:grid;gap:10px;padding-block:12px}
.mgroup>.btn,.mbadd .btn{min-height:44px;width:100%;display:flex;align-items:center;justify-content:center}
.mbadd{display:grid;gap:8px;margin-block-start:14px}
.march{margin-block-start:16px}
.march summary{min-height:44px;display:flex;align-items:center;cursor:pointer;font-weight:600;color:var(--brand-text)}
.plist{list-style:none;margin:0;padding:0;display:grid}
.plist li{display:flex;justify-content:space-between;gap:10px;padding-block:8px;border-block-end:1px dashed var(--line);overflow-wrap:anywhere}
.plist li.g{font-weight:700}
.plist li.k{padding-inline-start:16px;color:var(--muted)}
.ptotal{margin-block-start:10px}
.msave{position:sticky;bottom:0;z-index:5;display:grid;gap:8px;padding-block:10px;background:var(--page)}
.msave .btn{min-height:44px;display:flex;align-items:center;justify-content:center;width:100%}
@media (min-width:640px){
  .mrow{grid-template-columns:minmax(0,2fr) 110px 110px}
  .mrow .mname{grid-column:auto}
  .mbadd{display:flex}
  .mgroup>.btn,.mbadd .btn{width:auto;min-width:180px}
  .msave{display:flex;justify-content:flex-start}
  .msave .btn{width:auto;min-width:160px}
}
@media (min-width:900px){
  .mbgrid{grid-template-columns:minmax(0,1.6fr) minmax(0,1fr);align-items:start}
  .mprev{position:sticky;top:12px}
}
.mnum{min-width:0}
.mgname{min-width:0}
.msave{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr)}
@media (min-width:640px){.msave{grid-template-columns:none}}

/* Accounts (admin): one card per account on a phone instead of a table that scrolls sideways. */
@media (max-width:639px){
  .acct,.acct tbody,.acct tr,.acct td{display:block;width:100%}
  .acct thead{display:none}
  .acct tr{padding:12px;margin-block:10px;border:1px solid var(--line);border-radius:var(--radius-card);background:var(--card)}
  .acct td{padding:2px 0;border:0;background:none;text-align:start;overflow-wrap:anywhere}
  .acct td.num{display:grid;gap:8px;margin-block-start:10px}
  .acct td.num form{display:block;width:100%}
  .acct td.num .btn{width:100%;min-height:44px;display:flex;align-items:center;justify-content:center}
}

/* ----- Roster as a table: cells on a phone, columns on a wide screen (mockup 3) ----- */
.rhead{display:none}
.rcard .rpick{grid-row:1 / span 7}
.rcell{min-width:0;overflow-wrap:anywhere;font-size:14px}
.rcell.rorig{color:var(--muted);font-size:13px}
.rcell[data-l]::before{content:attr(data-l) ": ";color:var(--muted);font-size:12px}
.rcell.rplan{display:grid;gap:4px}
.rcell.rplan::before{display:block}
.prog{height:8px;border-radius:99px;background:var(--line);overflow:hidden;min-width:56px}
.prog i{display:block;height:100%;background:var(--ok);border-radius:99px}
.prog.lag i{background:var(--warn)}
.kpi2 .d.warn{color:var(--warn)}
.rlist .btn.ropen{background:transparent}
@media (min-width:900px){
  .rlist{grid-template-columns:1fr}
}
@media (min-width:1200px){
  .rlist{gap:0;border:1px solid var(--line);border-radius:var(--radius-card);background:var(--card);overflow:hidden}
  .rhead,.rcard{display:grid;grid-template-columns:44px minmax(120px,1.5fr) minmax(90px,1fr) minmax(100px,1fr) minmax(110px,1.1fr) minmax(110px,1.2fr) minmax(130px,1.6fr) 72px;
    gap:8px;align-items:center;padding:8px 10px}
  .rhead{background:var(--surface);font-size:12px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
  .rcard{border:0;border-radius:0;border-top:1px solid var(--line)}
  .rcard .rpick{grid-row:auto}
  .rcell[data-l]::before{display:none}
  .rcell.rplan::before{display:none}
  .ropen{grid-column:auto;min-width:64px}
}
/* phone: keep each roster card short */
.rcard{gap:2px 10px;padding:10px 12px}
.rcard .rpick{align-self:start}
.rcell{line-height:1.35}
.rcell.rwho .hint{margin:0;font-size:12.5px}
.rcell.rplan{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-height:28px}
.rcell.rplan::before{content:attr(data-l) ": ";display:inline}
.rcell.rplan .prog{flex:1 1 60px}
.rcell.rplan .hint{font-size:12.5px}
@media (min-width:1200px){.rcell.rplan{flex-wrap:nowrap;flex-direction:column;align-items:stretch;gap:3px}.rcell.rplan::before{display:none}}
@media (min-width:1200px){
  .rhead,.rcard{grid-template-columns:36px minmax(0,1.4fr) minmax(0,1fr) minmax(0,1fr) minmax(0,1fr) minmax(0,1.1fr) minmax(0,1.4fr) 64px;gap:6px;padding:8px}
  .rcell.rplan .prog{flex:none;width:100%}
  .rcell{font-size:13px}
  .rcard .ropen{padding-inline:8px;min-width:0}
}

/* ----- Requests waiting on a trainer (mockup 2 and 6) ----- */
.preq{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px 12px;align-items:center;padding-block:10px;border-bottom:1px solid var(--line)}
.preq:last-of-type{border-bottom:0}
.preq .av{width:44px;height:44px;border-radius:50%;background:var(--brand-tint-2);color:var(--brand-text);display:grid;place-items:center;font-weight:800}
.preq .pwho{min-width:0;overflow-wrap:anywhere}
.preq .pact{grid-column:1 / -1;display:grid;gap:8px}
.preq .pact .btn,.preq .pact summary{min-height:44px;display:flex;align-items:center;justify-content:center;width:100%}
.preq details>summary{list-style:none;cursor:pointer}
.preq details>summary::-webkit-details-marker{display:none}
.dpanel{display:grid;gap:10px;margin-block-start:10px;padding:12px;background:var(--surface);border-radius:var(--radius-card)}
.rchoice{display:flex;flex-wrap:wrap;gap:8px}
.rc{position:relative;cursor:pointer}
.rc input{position:absolute;opacity:0;inset:0;width:100%;height:100%;margin:0;cursor:pointer}
.rc span{display:inline-flex;align-items:center;min-height:44px;padding:8px 14px;border:1px solid var(--line-strong);border-radius:var(--radius-pill);background:var(--card);font-size:14px}
.rc input:checked+span{background:var(--brand-tint-2);border-color:var(--brand);color:var(--brand-text);font-weight:700}
.rc input:focus-visible+span{outline:2px solid var(--brand);outline-offset:2px}
.dbtns{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.dbtns .btn{min-height:44px;display:flex;align-items:center;justify-content:center}
.preq .pact{display:flex;flex-wrap:wrap}
.preq .pact>.btn{flex:1 1 140px}
.preq details{flex:1 1 140px}
.preq details[open]{flex-basis:100%}

/* ----- My Coach rows, search results and switches (mockups 1 and 9) ----- */
.prow{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px 12px;align-items:center;padding-block:10px;border-bottom:1px solid var(--line)}
.prow:last-child{border-bottom:0}
.prow .av{width:44px;height:44px;border-radius:50%;background:var(--brand-tint-2);color:var(--brand-text);display:grid;place-items:center;font-weight:800;flex:none}
.prow .pwho{min-width:0;overflow-wrap:anywhere}
.prow .pwho .pill{margin-inline-start:4px;vertical-align:middle}
.prow>.btn,.prow>.hint,.prow>.pact{grid-column:1 / -1}
.prow>.btn{min-height:44px;display:flex;align-items:center;justify-content:center}
.prow .pact{display:flex;flex-wrap:wrap;gap:8px}
.prow .pact>.btn,.prow .pact summary{flex:1 1 140px;min-height:44px;display:flex;align-items:center;justify-content:center}
.prow details{flex:1 1 140px}
.prow details[open]{flex-basis:100%}
.prow details>summary{list-style:none;cursor:pointer}
.prow details>summary::-webkit-details-marker{display:none}
@media (min-width:640px){
  .prow{grid-template-columns:auto minmax(0,1fr) auto}
  .prow>.btn,.prow>.hint{grid-column:auto}
  .prow .pact{grid-column:1 / -1}
}
.cresults{margin-block:10px;border-radius:var(--radius-card)}
.cresults .prow{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);padding:8px 10px;margin-block-end:8px}
.cresults .prow:last-child{border-bottom:1px solid var(--line)}
#coach-q{width:100%;min-height:48px;font-size:16px;border:1px solid var(--line-strong);border-radius:var(--radius-field);padding:10px 12px;background:#fff;color:var(--ink);font-family:inherit}
.swrow{display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px;align-items:start;padding-block:12px;border-bottom:1px solid var(--line)}
.swrow:last-child{border-bottom:0}
.switch{width:56px;height:44px;border:0;background:transparent;padding:0;cursor:pointer;display:flex;align-items:center}
.switch i{position:relative;display:block;width:52px;height:30px;border-radius:99px;background:var(--line-strong);transition:var(--t)}
.switch i::after{content:"";position:absolute;inset-block-start:3px;inset-inline-start:3px;width:24px;height:24px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(1,27,47,.3);transition:var(--t)}
.switch.on i{background:var(--ok)}
.switch.on i::after{inset-inline-start:25px}
.switch:focus-visible i{outline:2px solid var(--brand);outline-offset:2px}

/* ----- Admin: an application, as in mockup 5 ----- */
.reqhead{display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px;align-items:start}
.reqhead .av{width:44px;height:44px;border-radius:50%;background:var(--brand-tint-2);color:var(--brand-text);display:grid;place-items:center;font-weight:800}
.reqwho{min-width:0;overflow-wrap:anywhere}
.reqwho .pill{margin-inline-start:4px;vertical-align:middle}
.reqwhy{display:grid;gap:8px;padding:12px;background:var(--surface);border-radius:var(--radius-card)}
.reqform .rchoice{display:flex}
.reqform .rc input{width:100%;min-height:0}

/* ----- One athlete: module card with last values and a trend (mockup 4) ----- */
.tabhint{margin:-6px 0 12px}
.modcard{border:1px solid var(--line);border-radius:var(--radius-card);padding:12px;margin-block-end:12px}
.modhead{display:flex;flex-wrap:wrap;gap:6px 8px;align-items:center;margin-block-end:8px}
.modhead .sub{color:var(--muted);font-size:13px}
.modcard .vals{display:grid;gap:2px}
.modcard .v{display:grid;grid-template-columns:minmax(0,1fr) auto 92px;gap:8px;align-items:center;min-height:36px;border-bottom:1px dashed var(--line)}
.modcard .v.child{padding-inline-start:16px;color:var(--body);font-size:14px;grid-template-columns:minmax(0,1fr) auto 92px}
.modcard .v b{overflow-wrap:anywhere}
.sparkbox{color:var(--ok);display:block;height:22px}
.spark{width:90px;height:22px}
.modcard .actions{display:flex;flex-wrap:wrap;gap:8px;margin-block-start:10px}
.modcard .actions .btn{min-height:44px;display:flex;align-items:center;justify-content:center;flex:1 1 140px}

/* ----- Module builder: reorder, summary, preview guides (mockup: module, one page) ----- */
.mmove{grid-column:1 / -1;display:flex;justify-content:flex-end;gap:6px}
.mmove .btn{min-width:44px;min-height:44px;padding:0;display:flex;align-items:center;justify-content:center}
.mgroup-h .mmove{justify-content:flex-start}
.msum{margin:0 0 12px;padding:10px 12px;background:var(--surface);border-radius:var(--radius-card);color:var(--body)}
.pdate{margin:0 0 8px}
.plist .pguide{display:block;flex-basis:100%;color:var(--muted);font-size:12.5px}
.plist li{flex-wrap:wrap}

/* ----- Phone filter sheet: tags, a grab bar, and an Apply button that counts (mockup 3b) ----- */
.fpanel.sheet::before{content:"";display:block;width:44px;height:5px;border-radius:99px;background:var(--line-strong);margin:0 auto 10px}
.fpanel.sheet .fgroup{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.fpanel.sheet .fgroup legend{flex:0 0 100%;float:left;width:100%}
.fpanel.sheet .fopt{position:relative;display:inline-flex;gap:6px;min-height:44px;padding:6px 14px;border:1px solid var(--line-strong);border-radius:var(--radius-pill);background:var(--card)}
.fpanel.sheet .fopt input{position:absolute;opacity:0;inset:0;width:100%;height:100%;margin:0;cursor:pointer}
.fpanel.sheet .fopt:has(input:checked){background:var(--brand-tint-2);border-color:var(--brand);color:var(--brand-text);font-weight:700}
.fpanel.sheet .fopt:has(input:focus-visible){outline:2px solid var(--brand);outline-offset:2px}
.fpanel.sheet .fopt .c{margin-inline-start:2px;font-size:12px}
.fpanel.sheet .fmore{flex:0 0 100%}
.fpanel.sheet .fmore[open]{display:flex;flex-wrap:wrap;gap:8px}
.fpanel.sheet .fmore summary{flex:0 0 100%}
.fpanel.sheet .ffoot{grid-template-columns:auto 1fr;align-items:center}
.fpanel.sheet .ffoot .btn:first-child{order:2}
.fpanel.sheet .ffoot .btn:last-child{order:1}
.ptasks{display:grid;gap:2px;margin-block:4px 12px}
.ptasks .v{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:8px;align-items:center;min-height:40px;border-bottom:1px dashed var(--line)}
@media (max-width:480px){.ptasks .v{grid-template-columns:minmax(0,1fr) auto}.ptasks .v .pill{grid-column:1 / -1;justify-self:start}}
.welcome{margin-block-end:12px}
.welcome h2{margin:0;font-size:20px}
.rcell.rlast,.rcell.rcomp{min-width:0}
.fcity{width:100%;min-height:44px;font-size:16px;border:1px solid var(--line-strong);border-radius:var(--radius-field);padding:8px 12px;font-family:inherit}
.rc-note{margin:0}
.rc span{text-transform:none;letter-spacing:0;font-size:14px}
.reqform .rc{display:inline-block}
.reqform label.rc span,.rc span{text-transform:none !important;letter-spacing:0 !important;font-size:14px !important;color:inherit}
.reqform .rc input:checked+span{color:var(--brand-text)}

/* Competition records on a phone: one card per result, no sideways scroll */
@media (max-width:639px){
  .comptbl thead{display:none}
  .comptbl,.comptbl tbody,.comptbl tr,.comptbl td{display:block;width:100%}
  .comptbl tr{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 10px;padding:10px 4px;border-bottom:1px solid var(--line)}
  .comptbl td{padding:0;border:0;text-align:start;background:none}
  .comptbl td.cw{grid-column:1 / -1;grid-row:2;font-weight:600;overflow-wrap:anywhere}
  .comptbl td.cd{grid-row:1;color:var(--muted);font-size:13px}
  .comptbl td.cr{grid-row:1;grid-column:2;text-align:end;color:var(--muted);font-size:13px}
  .comptbl td.cc{grid-row:3;color:var(--body)}
  .comptbl td.ct{grid-row:3;grid-column:2;text-align:end;font-weight:700}
}
@media (max-width:639px){
  .t.comptbl tbody tr td{background:none !important;border:0 !important;padding:0 !important;min-height:0;line-height:1.35}
  .t.comptbl tbody tr{background:none !important;border-bottom:1px solid var(--line) !important}
  .t.comptbl td .hint{margin:0;font-size:12px}
}

/* Accounts page (app/users.php): four filters in one row that wraps, and the
   last-sign-in cell stacking "3 h ago" over the exact time. */
.acctfilter{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;align-items:end;margin-block-end:14px}
.acctfilter-go{display:flex;gap:8px;flex-wrap:wrap}
td.lastlogin{white-space:nowrap}
td.lastlogin .sub2{display:block;font-size:12px;color:var(--muted)}
.acctpager{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px;margin-block-start:14px}
.acctpager-go{display:flex;align-items:center;gap:10px;flex-wrap:wrap}

/* The sport picker (inc/sport_pick.php): one control, in the body of the page and
   never in the top bar, so on a phone it is not a strip above the content.
   Tokens only; background-color, never the shorthand, so the select keeps its chevron. */
.sportpick{display:flex;flex-direction:column;gap:6px;margin-block-end:16px}
.sportpick label{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:700}
.sportpick-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.sportpick select{flex:1 1 200px;min-width:0;max-width:420px;height:44px;min-height:44px;box-sizing:border-box;border:1.5px solid var(--brand);border-radius:8px;padding-inline:12px;font-weight:700;color:var(--brand-text);background-color:var(--card)}
.sportpick-one{font-weight:800;font-size:16px;color:var(--brand-text)}
