@import '_content/Microsoft.FluentUI.AspNetCore.Components/Microsoft.FluentUI.AspNetCore.Components.bundle.scp.css';

/* /Components/Layout/TableLayout.razor.rz.scp.css */
/* The shell holds the card in the middle of the phone and gets out of the way.

   No max-width beyond a comfortable reading measure: this is read on a phone held at arm's length,
   and on the rare desktop visit a card stretched across a monitor would be worse, not better. */
.table-shell[b-6xrehfs5gv] {
    display: block;
    box-sizing: border-box;
    width: 100%;
    max-width: 32rem;
    margin: 0 auto;
    padding: 1.5rem 1rem 3rem;
}
/* /Components/Pages/Home.razor.rz.scp.css */
/* The front page, laid out for a phone held at arm's length in a lit hall.

   Three blocks, in the order the page reads: your own game, the room's boards, the table everybody
   is playing for. Everything here is sized so that the whole page fits 375px with no horizontal
   scroll at any point — that is the constraint the three issues behind this file share, and the one
   a data grid could not have met (see the comments in Home.razor).

   Colours are FluentUI design tokens rather than hex values. Light theme only, as everywhere in this
   app: a settled decision, not an omission. */

/* ===========================================================================
   Your own game
   ===========================================================================
   It was a FluentMessageBar with Intent="Info" — the costume of a dismissible
   hint on the least dismissible fact in the application — with a separate
   button underneath. It is now one control: the block IS the link. */

.my-board[b-1bgcoz9zfl] {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    width: 100%;
    padding: 0.9rem 1rem;
    border: 2px solid var(--colorBrandStroke1, var(--colorNeutralForeground1));
    border-radius: 0.5rem;
    background: var(--colorBrandBackground2, var(--colorNeutralBackground1Selected));
    color: inherit;
    text-decoration: none;
}

/* The bye. Same block, nothing to press: there is no board to walk to, so the brand fill would be
   an affordance promising something. */
.my-board-quiet[b-1bgcoz9zfl] {
    border-color: var(--colorNeutralStroke1);
    background: var(--colorNeutralBackground3);
}

.my-board:focus-visible[b-1bgcoz9zfl] {
    outline: 2px solid var(--colorStrokeFocus2, var(--colorNeutralForeground1));
    outline-offset: 2px;
}

.my-board-label[b-1bgcoz9zfl] {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--colorNeutralForeground3);
}

.my-board-body[b-1bgcoz9zfl] {
    display: flex;
    align-items: center;
    gap: 0.9rem;
}

/* The answer to the question somebody opened the app to ask, at the size that answers it from
   across a room. clamp() rather than a fixed size: 12vw is what makes it hero-sized on the phone
   this is read on without becoming absurd on a monitor. */
.my-board-number[b-1bgcoz9zfl] {
    flex: 0 0 auto;
    min-width: 1.6ch;
    font-size: clamp(2.5rem, 12vw, 3.25rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.my-board-lines[b-1bgcoz9zfl] {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.my-board-colour[b-1bgcoz9zfl],
.my-board-versus[b-1bgcoz9zfl] {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--colorNeutralForeground3);
}

/* Sits directly over the name it names. Without it the colour above was reading as the opponent's,
   because a small grey line over a large bold one is the shape of a label over its value. */
.my-board-versus[b-1bgcoz9zfl] {
    margin-top: 0.2rem;
}

/* Names are data and some of them are long. Wrapping beats truncating: a player whose opponent's
   name is cut off cannot tell whether they are reading their own board. */
.my-board-opponent[b-1bgcoz9zfl] {
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.25;
    overflow-wrap: anywhere;
}

/* The affordance, spelled out. The whole block is the tap target — this line is what says so, and
   it is the sentence the old button carried, so nothing was renamed on the way. */
.my-board-go[b-1bgcoz9zfl] {
    display: inline-flex;
    align-items: center;
    min-height: 1.75rem;
    font-weight: 600;
    color: var(--colorBrandForegroundLink, var(--colorNeutralForeground1));
}

.my-board-go[b-1bgcoz9zfl]::after {
    content: " \2192";
    margin-inline-start: 0.35rem;
}

.my-board-said[b-1bgcoz9zfl] {
    font-size: 1.05rem;
    line-height: 1.3;
}

/* ===========================================================================
   The round's boards
   ===========================================================================
   Rows, never a grid: below ~500px a data grid clips its columns instead of
   scrolling, and /manage/rounds/{id} shows one player of a pairing at 375px
   because of exactly that (#25 B4). A board is a number and two names. */

.boards h2[b-1bgcoz9zfl],
.ranking h2[b-1bgcoz9zfl] {
    margin: 0;
}

.board-list[b-1bgcoz9zfl] {
    list-style: none;
    margin: 0.5rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.board[b-1bgcoz9zfl] {
    border: 1px solid var(--colorNeutralStroke2);
    border-radius: 0.5rem;
    background: var(--colorNeutralBackground1);
}

/* Your own row, told apart from the other nineteen by more than its position. It is also the only
   one that goes anywhere. */
.board-mine[b-1bgcoz9zfl] {
    border-color: var(--colorBrandStroke1, var(--colorNeutralForeground1));
    border-width: 2px;
}

/* The row is a <div>. It was an <a> — href on your own board, absent on every other row, one markup
   for both forms — and #44 took that away rather than adding to it: the two names inside are links
   to /players/{slug} now, and an `a` may not contain an `a`. An href-less anchor is no exception;
   its content model is transparent and still excludes them. Blazor builds the DOM with
   createElement rather than through the parser, so nesting them would have rendered and been wrong.

   What the row lost is a 375px-wide tap target on ONE row out of twenty. What it did not lose is
   the way to your table: that moved to .board-yours, which is the only part of the row that was
   ever about going somewhere, and the hero block at the top of the page is untouched and still the
   loudest thing on the page. */
.board-row[b-1bgcoz9zfl] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.75rem;
    color: inherit;
}

/* The table number, in a column of its own so twenty rows line up down the page and the eye can run
   to table 7 without reading the names on the way. */
.board-number[b-1bgcoz9zfl] {
    flex: 0 0 2rem;
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.1;
    text-align: center;
    color: var(--colorNeutralForeground2);
    font-variant-numeric: tabular-nums;
}

.board-sides[b-1bgcoz9zfl] {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    flex: 1 1 auto;
}

/* The disc, then BoardPlayer. No ::deep needed on the disc — it is written in Home.razor — and none
   is possible for BoardPlayer's insides, which is why its own stylesheet travelled with it into
   Components/Shared. */
.board-side[b-1bgcoz9zfl] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}

.board-yours[b-1bgcoz9zfl] {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--colorBrandForeground1, var(--colorNeutralForeground1));
}

/* The marker is the link when the board is yours and is not a bye — it carries what the whole row
   used to carry. Sized as a target rather than as a caption: 2rem and an arrow, on its own line
   above the two players, so a thumb aiming at "your table" cannot land on your opponent's name
   instead. Not the full 2.75rem this app gives a lone destination — the hero block at the top of
   the page is that control, and this is the second way to the same place. */
.board-yours-link[b-1bgcoz9zfl] {
    display: inline-flex;
    align-items: center;
    min-height: 2rem;
    text-decoration: none;
    cursor: pointer;
}

.board-yours-link[b-1bgcoz9zfl]::after {
    content: " \2192";
    margin-inline-start: 0.3rem;
}

.board-yours-link:hover[b-1bgcoz9zfl],
.board-yours-link:focus-visible[b-1bgcoz9zfl] {
    text-decoration: underline;
}

/* A bye is a null opponent in the schema. On screen it has to be a word, or the second line of the
   row is a blank that reads as a name that failed to load. Indented to the width of a disc and its
   gap so it sits under the player rather than under the table number. */
.board-bye[b-1bgcoz9zfl] {
    margin-inline-start: 1.9rem;
    padding: 0.35rem 0.6rem;
    color: var(--colorNeutralForeground3);
}

/* ===========================================================================
   The standings
   ===========================================================================
   Rank, name, score. Three columns that do not grow with the round count —
   #24 measured the per-round run at 280 + 17.6n px, which puts the score off a
   375px screen from six rounds. The run lives on /standings/{id}. */

.ranking-caption[b-1bgcoz9zfl] {
    margin: 0.25rem 0 0.75rem;
    color: var(--colorNeutralForeground3);
}

.rank-list[b-1bgcoz9zfl] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.rank-row[b-1bgcoz9zfl] {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
    padding: 0.6rem 0.25rem;
    border-bottom: 1px solid var(--colorNeutralStroke2);
}

.rank-row:last-child[b-1bgcoz9zfl] {
    border-bottom: none;
}

.rank-place[b-1bgcoz9zfl] {
    flex: 0 0 1.75rem;
    text-align: end;
    color: var(--colorNeutralForeground3);
    font-variant-numeric: tabular-nums;
}

/* Takes the slack, and wraps rather than clipping. This is the column that would have been squeezed
   to nothing if a per-round run were sitting to the right of it. */
.rank-name[b-1bgcoz9zfl] {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 600;
    overflow-wrap: anywhere;
}

/* Last, because it is the answer the other two columns are the working for. */
.rank-score[b-1bgcoz9zfl] {
    flex: 0 0 auto;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* ===========================================================================
   The ways onward
   ===========================================================================
   The full table, and the club's history. Both are links rather than buttons:
   they are places to go, not things to do, and the page has no actions. */

.onward[b-1bgcoz9zfl] {
    display: flex;
    margin: 0;
}

.onward a[b-1bgcoz9zfl] {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    color: var(--colorBrandForegroundLink, var(--colorNeutralForeground1));
    font-weight: 600;
}

.onward a[b-1bgcoz9zfl]::after {
    content: " \2192";
    margin-inline-start: 0.35rem;
}
/* /Components/Pages/Manage/AuditLogPage.razor.rz.scp.css */
/* The device id doubles as the control that filters by it. A FluentButton would dominate a grid
   cell and set its own colours inside a shadow root; this is a link that happens to be a button,
   which is what it has to be to run an event handler. */
.device-filter[b-h1td4p8l6v] {
    background: none;
    border: none;
    padding: 0;
    font-family: var(--fontFamilyMonospace, monospace);
    font-size: inherit;
    color: var(--colorBrandForegroundLink, currentColor);
    cursor: pointer;
    text-decoration: underline;
}

.device-filter:hover[b-h1td4p8l6v] {
    color: var(--colorBrandForegroundLinkHover, currentColor);
}
/* /Components/Pages/Manage/People.razor.rz.scp.css */
/* The people page: the panels that open above the list. The list itself is a DataGrid and is
   styled by wwwroot/app.css, where the row height for the whole app lives — CSS isolation cannot
   reach a grid cell, because those are generated inside FluentDataGrid rather than written here. */

/* The sign-in name under a person's own name, and the handles under their phone number: secondary,
   not disabled. Color.Disabled is the token for a control nobody can use and reads that way. */
.username[b-hz5ohbk0ug] {
    font-size: var(--fontSizeBase200);
    line-height: var(--lineHeightBase200);
    color: var(--colorNeutralForeground3);
}

/* The handles under the phone number, each behind the mark of the site it belongs to. Wrapping
   rather than one line: two long handles and a narrow Contact column would otherwise widen the
   column at the expense of the name beside it. */
.person-handles[b-hz5ohbk0ug] {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 12px;
}

.person-handle[b-hz5ohbk0ug] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--fontSizeBase200);
    line-height: var(--lineHeightBase200);
    color: var(--colorNeutralForeground3);
}

/* The form itself — the fields and the photo — moved to ProfileEditor, and its rules went with it:
   CSS isolation is per component, so a rule left here would no longer reach the markup it was
   written for. See Components/Shared/ProfileEditor.razor.css. */

/* `.person-link` used to be here — a person's name in the grid, linking to the profile the rest of
   the club sees, underlined only on hover. #44 made every name in the app that link, so the rule is
   now `.player-link` in wwwroot/app.css and this page uses it like the other five do. The reasoning
   went with it; only the name and the file changed. */

/* The handover card: a username and a password to be read out across a hall.

   Deliberately the largest text on the page. It is read aloud once, from a phone held at arm's
   length, to somebody who will type it wrong if a lowercase l and a digit 1 look the same — so it
   is monospaced, spaced out, and selectable. */
.handover[b-hz5ohbk0ug] {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: baseline;
    gap: 8px 16px;
}

.handover-label[b-hz5ohbk0ug] {
    font-size: var(--fontSizeBase200);
    color: var(--colorNeutralForeground3);
    white-space: nowrap;
}

.handover-value[b-hz5ohbk0ug] {
    font-family: var(--fontFamilyMonospace);
    font-size: var(--fontSizeBase600);
    letter-spacing: 0.05em;
    user-select: all;
    word-break: break-all;
}
/* /Components/Pages/Manage/TableCards.razor.rz.scp.css */
/* The preview, and nothing else — the cards are drawn by QuestPDF now, in millimetres, inside the
   PDF that this frame is showing (Printing/TableCardDocument.cs).

   There is deliberately no @media print block in this file any more, and none should come back. The
   page used to lay the cards out in HTML and hand them to the browser's print engine, which meant
   two descriptions of one artefact — a screen one and a paper one — that could disagree without
   anything failing. They did: a five-page sheet printed as one page and the screen looked correct
   right up to the fold (docs/diary/2026-08-04-chess-gl0-qr-table-cards.md). Printing this page now
   prints a screenshot of a PDF viewer, which is nobody's intention; the Print button prints the
   file. */

/* Two frames, one rule: the cards and the score sheets are both A4 documents in a browser's own
   PDF viewer, and a second set of numbers for the second one would only be a chance for them to
   drift. The classes stay separate so a test can say which document it is looking at. */
.cards-preview[b-ieivho8rbm],
.sheet-preview[b-ieivho8rbm] {
    width: 100%;
    /* Tall enough to show a whole A4 page at a readable size on a laptop, and to make it obvious
       this is a document rather than a thumbnail. The viewer inside scrolls. */
    height: 80vh;
    min-height: 400px;
    border: 1px solid var(--colorNeutralStroke1);
    border-radius: var(--borderRadiusMedium);
    /* A PDF viewer paints its own background; this is the sliver around it before it loads. */
    background: var(--colorNeutralBackground3);
}

/* The second document on the page. The rule above it is the whole separation: one errand, two
   artefacts, and a manager scrolling past the cards' preview needs to see that something else
   starts here. */
.printable-section[b-ieivho8rbm] {
    width: 100%;
    padding-top: 24px;
    border-top: 1px solid var(--colorNeutralStroke2);
}

/* The h2 and its two buttons, on one line while there is room for one. Same shape as PageHeading's
   own header row, at the size a section heading takes. */
.section-heading[b-ieivho8rbm] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 16px;
    width: 100%;
}

.section-heading h2[b-ieivho8rbm] {
    margin: 0;
}

.section-heading-actions[b-ieivho8rbm] {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Capped at the same measure as a page description, and for the same reason: a sentence running the
   full width of a monitor is skipped rather than read. */
.section-description[b-ieivho8rbm] {
    margin: 0;
    color: var(--colorNeutralForeground2);
    max-width: 80ch;
}
/* /Components/Pages/Manage/TournamentEditor.razor.rz.scp.css */
/* The tournament's own list of players.

   Hand-rolled rather than FluentDataGrid because this is a club-sized list that needs no
   virtualisation, paging or column sorting, and because it sits under a form rather than owning the
   page. Every colour is a Fluent design token, so a theme change needs no second rule.

   Moved here from Roster.razor.css when /manage/roster was deleted and enrolment came onto the
   tournament page (chess-1kz). */

/* The section title and its count on one baseline: "Players   12 players, 1 withdrawn". */
.players-heading[b-tq0ln99tt3] {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 12px;
}

.players-heading h2[b-tq0ln99tt3] {
    margin: 0;
}

.players-scroll[b-tq0ln99tt3] {
    /* The table scrolls inside itself on a narrow screen rather than pushing the page sideways. */
    overflow-x: auto;
    width: 100%;
}

.players[b-tq0ln99tt3] {
    width: 100%;
    border-collapse: collapse;
    /* Names are the wide column; everything else takes what it needs. */
    min-width: 34rem;
}

/* The same row as a DataGrid's, from the same variable: this table sits one click from the grids on
   the tournament list and audit pages and has no business being a different height.
   --row-min-height is declared in wwwroot/app.css, which is also where the grids' own rule reads
   it. */
.players th[b-tq0ln99tt3],
.players td[b-tq0ln99tt3] {
    text-align: left;
    height: var(--row-min-height);
    padding: 6px 12px;
    vertical-align: middle;
    border-bottom: 1px solid var(--colorNeutralStroke2);
}

/* The name cell is two stacked lines, so it aligns to the top of the row rather than being centred
   against a single-line score beside it. */
.players td:first-child[b-tq0ln99tt3] {
    vertical-align: top;
    padding-top: 8px;
}

/* `position: relative` is load-bearing, not decoration. The action column's header is an
   absolutely positioned .sr-only span, and without a positioned cell to resolve against it takes
   its containing block from outside the scroller — so it kept its static offset inside a 544px
   table and dragged the whole document's scrollWidth to 524px on a 375px phone. The table scrolled
   inside its box exactly as intended and the page scrolled sideways anyway. Containing the span in
   its own cell is the fix. (Carried over from Roster.razor.css, where it had the same effect.) */
.players th[b-tq0ln99tt3] {
    position: relative;
    font-weight: var(--fontWeightSemibold);
    font-size: var(--fontSizeBase200);
    color: var(--colorNeutralForeground3);
    white-space: nowrap;
}

/* The add field: as wide as a name needs, not as wide as the page. Left to grow it reached the far
   side of a 1440px monitor and put the Add button a metre from the field it belongs to. It still
   shrinks below 22rem on a phone. */
.add-field[b-tq0ln99tt3] {
    flex: 1 1 22rem;
    max-width: 30rem;
}

/* The player's own name, which is a link to their profile now (#44). Block, because the sign-in
   name goes underneath it — that is what the FluentText it replaced was doing with Block="true" —
   and semibold, which is what it always was. Colour and underline come from `.player-link`. */
.roster-name[b-tq0ln99tt3] {
    display: block;
    font-weight: 600;
}

/* The sign-in name under a player's own name: secondary, not disabled. */
.username[b-tq0ln99tt3] {
    font-size: var(--fontSizeBase200);
    line-height: var(--lineHeightBase200);
    color: var(--colorNeutralForeground3);
}

.players .numeric[b-tq0ln99tt3] {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Shrink-to-fit: the name column takes the slack. */
.players .actions[b-tq0ln99tt3] {
    width: 1%;
}

/* The buttons themselves are RowActions, which brings its own flex row — see
   Components/Shared/RowActions.razor.css. A copy of that rule here would not apply anyway: it is
   scoped to this page and the div belongs to that component. */

/* Withdrawn players stay on the list and stay legible — they are not deleted and their results
   still count. Dimmed enough to read as "not being paired", not so much as to read as gone. */
.players tr.withdrawn td[b-tq0ln99tt3] {
    opacity: 0.65;
}

/* Column headers that exist for screen readers only. */
.sr-only[b-tq0ln99tt3] {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
/* /Components/Pages/PlayerProfilePage.razor.rz.scp.css */
/* One person's profile: a photo, a name, and the accounts they play under. */

.player-head[b-lhu8kpycut] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 16px;
}

/* Larger than the 96px thumbnail on the editing form. This is the one page somebody came to look
   at the person, and a face at 96px on a phone held at arm's length is not recognisable. */
.player-photo[b-lhu8kpycut] {
    width: 144px;
    height: 144px;
    border-radius: var(--borderRadiusLarge);
    object-fit: cover;
    border: 1px solid var(--colorNeutralStroke2);
    background: var(--colorNeutralBackground3);
}

.player-photo-empty[b-lhu8kpycut] {
    display: flex;
    align-items: center;
    justify-content: center;
}

.player-name[b-lhu8kpycut] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
}

/* The base stylesheet sizes h1 for a page heading; this one sits next to a photograph and beside
   a badge, so it needs its margin taken off rather than its size changed. */
.player-name h1[b-lhu8kpycut] {
    margin: 0;
}

/* Site then handle, in two columns, so two handles line up under each other instead of reading as
   one run-on sentence. */
.player-handles[b-lhu8kpycut] {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: baseline;
    gap: 4px 16px;
}

/* The phone row's label, which is still a word. The handles' column is a logo instead — see
   .player-handle-mark below. */
.player-handle-site[b-lhu8kpycut] {
    font-size: var(--fontSizeBase200);
    color: var(--colorNeutralForeground3);
    white-space: nowrap;
}

/* The site's mark, in the column the site's name used to be in.

   A fixed width so the two marks share a centre line and the handles beside them start at the same
   place — the lichess knight is wider than the chess.com pawn, and left-aligning them would step
   the two handles apart by the difference.

   align-self overrides the grid's baseline for this cell only. A logo has no baseline worth
   aligning to: sitting it on the text's would hang it above the line it belongs to. */
.player-handle-mark[b-lhu8kpycut] {
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: center;
    width: 20px;
}
/* /Components/Pages/Standings.razor.rz.scp.css */
/* The per-round run, and the key that explains it.

   Light theme only, and colours are FluentUI design tokens rather than hex, so this stays in the
   same system as every other page. The screenshot this was modelled on is dark and its
   green-on-black does not transfer; what does transfer is the density.

   Colour here is the SECOND channel. The figures differ in shape — 1, half, 0, plus, dot — so the
   table still reads with colour switched off entirely, which is what a colour-blind player in a
   brightly lit hall is doing. Since the bye was ruled a full point it shares the win's green, so
   for that one pair shape is not the second channel but the only one — see .run-bye.

   THE COLOUR IS ON A CHIP BEHIND THE FIGURE, NOT ON THE FIGURE (#43). The character is what makes
   the paragraph above true, so it stays: a tinted box behind a 1 is still a 1 to somebody who
   cannot separate the green from the red. Do NOT go the last step to a plain coloured square —
   that is where this design stops being readable without colour, and it is the one thing this
   file exists to prevent.

   AND IT COST NO WIDTH. The run's grid track is `auto` because its width is data (see
   Standings.razor:70), and at six closed rounds #24 already has the score column off the right
   edge of a 375px phone. So the chip is paid for out of the figure's own box rather than added to
   it: the box went from 1.05em to 0.9em and the 2px gaps between chips spend the difference.
   Measured on /standings/3 (the seeded six-round fixture) at 375px: 105.75px before, 100.72px
   after. See docs/diary/2026-08-05-issue-43-44-*.md. */

/* One line, never two: a run that wrapped would stop meaning "slot 3 is round 3" and start meaning
   nothing. Below the width it needs, the grid scrolls instead — that is what .grid-scroll is for.

   The gap is what keeps the chips countable. Butted together, three wins in a row fuse into one
   green bar and the run stops being three rounds; 2px of the page showing through is the whole
   difference. It is a gap and not padding on the figures because a gap falls BETWEEN them — six
   chips need five of them, not twelve half-ones. */
.round-run[b-hpwbkew2wp] {
    display: inline-flex;
    white-space: nowrap;
    gap: 2px;
}

/* Fixed width per figure, not tabular-nums: half and plus are not digits, so the numeric alignment
   feature does not reach them. An explicit box is the only thing that puts every row's third mark
   over every other row's third mark — and now that the box is painted, it is also the chip.

   0.9em wide, which is 15.1px against the widest figure's 9.8px of ink: the chip still has ~2.6px
   of clear ground either side of a glyph, and it is 5px narrower per figure than the run that came
   before it. Do not read the weight below as buying that back — the box is a fixed width, so a
   lighter glyph inside it changes nothing about the column.

   1.05rem rather than the table's own size. This is the column somebody is squinting at from two
   metres away, and a half symbol is a compound glyph that loses its bar first.

   Weight normal, not 600 (#43). Bold was doing the job the chip does now, and two emphases on one
   figure is one too many — the run was the loudest thing in the table and it is a footnote to the
   score. */
.run-mark[b-hpwbkew2wp] {
    display: inline-block;
    width: 0.9em;
    text-align: center;
    font-size: 1.05rem;
    font-weight: normal;
    line-height: 1.3;
    border-radius: var(--borderRadiusMedium);
    font-variant-numeric: tabular-nums;
}

/* Background2 and not Background1 for both outcomes. Background1 is the near-white wash a tinted
   badge fills with (#f1faf1) and it is invisible from two metres on a white table — which is the
   distance this column is built for. Background2 is the tint that badge draws its BORDER in, so it
   is still the app's own tint ramp rather than a colour invented here, and it is the first step on
   that ramp a phone at arm's length can actually see. Foreground2 on it clears 7:1. */
.run-win[b-hpwbkew2wp] {
    background: var(--colorPaletteGreenBackground2);
    color: var(--colorPaletteGreenForeground2);
}

/* A draw is neither, and a neutral chip is what "neither" looks like. Present rather than absent:
   half a point is half the table's decisions, and a bare figure between two chips would read as a
   round with nothing in it — which is what the dot is for. */
.run-draw[b-hpwbkew2wp] {
    background: var(--colorNeutralBackground5);
    color: var(--colorNeutralForeground1);
}

/* Red, because the human asked for red — "a tiny background for win green, red for loss".

   STILL NOT THE DANGER RED. RedBackground3 is #d13438, the colour this app paints a destructive
   button; a lost game is an ordinary evening at a club and painting it as an error would be the
   page having an opinion. Background2 is the same soft tint the win's green comes from, one ramp,
   two hues. That reasoning survived the change of channel; only the conclusion about WHERE the
   colour sits moved. */
.run-loss[b-hpwbkew2wp] {
    background: var(--colorPaletteRedBackground2);
    color: var(--colorPaletteRedForeground2);
}

/* A point that was not played for, on the same green chip as a point that was. Ruled by the human
   on the standings run: a bye is a full point and should read as one — "win is win".

   The distinction still exists, and it is in the GLYPH. Somebody comparing two players on the same
   score can still see which of them got there without a game — the first tie-break's whole subject
   — because the mark is a + and not a 1. Shape carries the distinction, colour carries the value,
   which is the same two-channel rule the rest of this file is built on. Moving the colour onto a
   chip did not change that: the + is still a +.

   This was yellow, on the reasoning that a bye reads as "qualified" rather than "good" and stays
   apart from a win for a red-green reader. The human overruled the conclusion, not the reasoning:
   the value is what they want the colour to say.

   Do NOT come back with a slightly different green as a compromise — that path is already closed.
   GreenForeground3 was tried and resolves to #107c10 against GreenForeground1's #0e700e in this
   theme: two names, one colour, a distinction that existed only in the source. Either this green or
   a different channel; there is no third green. */
.run-bye[b-hpwbkew2wp] {
    background: var(--colorPaletteGreenBackground2);
    color: var(--colorPaletteGreenForeground2);
}

/* The quietest mark on the page, and deliberately so: it holds a round's place and says nothing.
   NO CHIP AT ALL — a tint behind it would give a round that never happened the same weight as one
   that did, and the run would lose the gaps that make it a run rather than a bar.

   Foreground3 and not the dimmer 4: at 4 the dot all but vanished on a phone — including in the
   key, where the one figure nobody has met before was the one nobody could see. */
.run-none[b-hpwbkew2wp] {
    color: var(--colorNeutralForeground3);
}

/* The name, which is now the way to the person (#44). `.player-link` in app.css carries the
   colour and the hover underline for every one of these in the app; the weight is this table's own
   and predates the link — the eye goes down the names and across to the score, and the names are
   the left-hand rail it does that along. Two classes so neither rule has to know about the other. */
.standings-name[b-hpwbkew2wp] {
    font-weight: 600;
}

/* The key. A row of figure-and-word pairs that wraps on a phone rather than scrolling.

   These rules only started working when the key stopped being a FluentText — CSS isolation does not
   stamp its scope attribute onto a child component's element, so `.round-key[b-…]` had never
   matched anything. See the comment in Standings.razor.

   The gaps are wider than they read on paper because a figure is a filled chip now: 4px between a
   chip and its word looked like the word was written on the chip, and 16px between pairs looked
   like one long sentence. */
.round-key[b-hpwbkew2wp] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 18px;
    margin: 0;
    color: var(--colorNeutralForeground2);
}

.round-key-lead[b-hpwbkew2wp] {
    white-space: nowrap;
}

.round-key-item[b-hpwbkew2wp] {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    white-space: nowrap;
}

/* ---------------------------------------------------------------------------------------------
   Width, which is half of what this ticket was for.

   The rules below are all `::deep`: the table is SafeDataGrid's markup, not this file's, so a
   plain scoped selector would never match it. The wrapper is ours, and the scope attribute it
   carries is also what outranks app.css. Both column rules are positional because a grid cell
   carries no class of its own — the header test in StandingsPageTests is what pins the order those
   numbers depend on.
   --------------------------------------------------------------------------------------------- */

/* app.css gives every grid a 44rem floor to scroll to, because a five-column manager grid clips
   itself into a phone rather than scrolling. 44rem is 704px, which is exactly the width
   docs/mobile-ux-review.md measured this table at with the score off the right edge.

   Four columns do not want a blanket floor. They want to be as wide as they actually need, which
   is what the two rules below say and what lets a short tournament's table fit a 351px window
   whole. The shared rule is left alone for every other grid. */
.standings-scroll[b-hpwbkew2wp]  table.data-grid-fullwidth {
    min-width: 0;
}

/* A name may take two lines rather than lose its end.

   v5's cell rule is `white-space: nowrap; overflow: hidden; text-overflow: ellipsis`, and the
   ellipsis never appears because the cell's own flex child overflows visibly past it — so the
   table read "Ayşe Gül Özt", clipped mid-letter, with nothing to say it had been cut. Wrapping
   fixes that, and 6.5rem is the floor that keeps a long Turkish name to TWO lines: the row is 44px
   and does not grow, so a third line is clipped exactly as the first version was. Two lines is
   what there is room for, and this is the width that buys them. */
.standings-scroll[b-hpwbkew2wp]  td:nth-child(2),
.standings-scroll[b-hpwbkew2wp]  th:nth-child(2) {
    min-width: 6.5rem;
    white-space: normal;
}

/* The run is never cut. It is the one column here whose width is a fact about the tournament
   rather than a layout choice, and half a run is worse than a run you scroll to — a clipped last
   figure reads as a round that was not played.

   `max-content` and not a number: nine rounds need nine figures. Without it the cell's inherited
   `overflow: hidden` sets its automatic minimum to zero, the track collapses to whatever is left
   over, and the end of the run disappears with no scrollbar to say so. Giving the run a real floor
   makes the table honestly too wide instead, and .grid-scroll then does what it is for. */
.standings-scroll[b-hpwbkew2wp]  td:nth-child(3),
.standings-scroll[b-hpwbkew2wp]  th:nth-child(3) {
    min-width: max-content;
}

/* ---------------------------------------------------------------------------------------------
   The ways onward: to the club's archive, and — signed out — into the claim flow
   ---------------------------------------------------------------------------------------------
   A link rather than a button: it is a place to go, not a thing to do, and this page has no
   actions. Same shape and the same 2.75rem tap box as the home page's and the table page's, which
   is the size a thumb aiming one-handed needs — on a phone this is the ONLY door to /tournaments
   (#19), so it is the one link here that must not be a 20px line of text.

   The claim invitation (#44) wears the same shape on purpose. It is the same kind of thing — a
   sentence that is entirely a destination — and a signed-out visitor is reaching for it with the
   same thumb. */
.onward[b-hpwbkew2wp] {
    display: flex;
    margin: 0;
}

.onward a[b-hpwbkew2wp] {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    color: var(--colorBrandForegroundLink, var(--colorNeutralForeground1));
    font-weight: 600;
}

.onward a[b-hpwbkew2wp]::after {
    content: " \2192";
    margin-inline-start: 0.35rem;
}
/* /Components/Pages/TablePage.razor.rz.scp.css */
/* Sized for a phone held at arm's length in a lit hall, by somebody who has two seconds and one
   thumb. Everything here is either bigger than the rest of the app or out of the way of what is.

   Colours come from the FluentUI base theme's design tokens rather than from hex values, so this
   card stays in the same system as every other page. Light theme only — a settled decision, not an
   omission: this is used in a bright room, often by older players, and a second theme would double
   the surface every future page has to be checked against. */

.round-line[b-0fpqgvunok] {
    margin: 0;
    color: var(--colorNeutralForeground3);
    font-size: 1rem;
}

/* The first thing you look at, and the thing you are checking you are in the right place. */
.table-number[b-0fpqgvunok] {
    margin: 0.15rem 0 1.5rem;
    font-size: clamp(2.5rem, 12vw, 3.5rem);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -0.02em;
}

.seats[b-0fpqgvunok] {
    list-style: none;
    margin: 0 0 1.5rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

/* The card, in both of its forms. `width: 100%` and the font resets are for the button form only —
   a <button> does not inherit the page's font and shrinks to its content — but they are harmless on
   the <div> and keeping one rule means the two forms cannot drift apart. */
.seat[b-0fpqgvunok] {
    display: flex;
    width: 100%;
    align-items: center;
    gap: 0.85rem;
    padding: 0.9rem 1rem;
    border: 1px solid var(--colorNeutralStroke2);
    border-radius: 0.5rem;
    background: var(--colorNeutralBackground1);
    font: inherit;
    color: inherit;
    text-align: start;
}

/* The seat as a control. 4rem rather than the 44px minimum: this is tapped standing at a board, on
   a phone held at arm's length, by somebody who has just finished a game — and it is the only thing
   on the screen competing for the thumb, so there is no reason to be mean with it. */
.seat-pick[b-0fpqgvunok] {
    min-height: 4rem;
    cursor: pointer;
}

/* Hover belongs to the seat NOBODY HAS REPORTED YET, and to nothing else.

   Two reasons, and the second is the load-bearing one. A pointer that can hover is the exception
   here rather than the rule, so the query keeps the whole effect off the phone this page is for.
   And a tap leaves :hover latched on afterwards on every mobile browser — so without the
   `seat-open` qualifier, the card somebody had just tapped was painted as HOVERED instead of as
   WON, and the fill that says who won was the thing the tap removed. Seen on a real page, not
   reasoned about (chess-0kh). Naming the open state is what stops hover and the result competing
   for one property; do not relax this selector back to `.seat-pick:hover`. */
@media (hover: hover) {
    .seat-open:hover[b-0fpqgvunok] {
        background: var(--colorNeutralBackground1Hover);
        border-color: var(--colorNeutralStroke1);
    }
}

/* Drawn rather than left to the browser, because the card has its own border radius and the default
   ring follows the box instead. Not :focus — a thumb tap would leave a ring behind on a screen
   nobody is navigating by keyboard. */
.seat-pick:focus-visible[b-0fpqgvunok] {
    outline: 2px solid var(--colorStrokeFocus2, var(--colorNeutralForeground1));
    outline-offset: 2px;
}

/* Who won, at a glance and before any figure is read. The fill is the signal; the mark below says
   which figure went on the scoresheet. Nothing is applied until somebody reports — an unreported
   board must not look like a board that was drawn. */
.seat-won[b-0fpqgvunok] {
    border-color: var(--colorBrandStroke1, var(--colorNeutralForeground1));
    background: var(--colorBrandBackground2, var(--colorNeutralBackground1Selected));
}

.seat-lost[b-0fpqgvunok] {
    opacity: 0.55;
}

.seat-drew[b-0fpqgvunok] {
    border-color: var(--colorNeutralStroke1);
    background: var(--colorNeutralBackground3);
}

/* The player's own figure — 1, ½ or 0 — in the chip at the end of their card. Deliberately NOT
   aria-hidden: it is the scoresheet, not decoration, and a screen reader that heard the name and
   nothing else would be missing the result on a closed round. */
.seat-mark[b-0fpqgvunok] {
    flex: 0 0 auto;
    margin-inline-start: auto;
    min-width: 2rem;
    font-size: 1.35rem;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.seat-won .seat-mark[b-0fpqgvunok] {
    color: var(--colorBrandForeground1, var(--colorNeutralForeground1));
}

/* The disc that says which colour a seat has moved to wwwroot/app.css. It is not a page rule any
   more: the home page draws the same disc in its "you are at table 4" block and once per row of the
   live round's board list, and a second copy here would be the first place the two drifted apart.
   See the "Which colour somebody has" section there. */

.seat-lines[b-0fpqgvunok] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.seat-colour[b-0fpqgvunok] {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--colorNeutralForeground3);
}

/* Names are data, and some of them are long. Wrapping beats truncating: a player whose name is cut
   off cannot tell whether they are looking at their own board. */
.seat-name[b-0fpqgvunok] {
    font-size: 1.35rem;
    font-weight: 600;
    line-height: 1.25;
    overflow-wrap: anywhere;
}

/* The third option, and the whole of the ticket's "small". Centred and hugging its own words rather
   than stretched across the card like the seats above it: a draw the same width as a player would
   read as a third player. */
.draw[b-0fpqgvunok] {
    display: flex;
    justify-content: center;
    margin: 0.25rem 0 1.25rem;
}

/* ::deep because a component's scoped CSS does not reach the markup another component renders, and
   FluentButton renders its own <fluent-button>. The wrapper above is ours, so descending from it
   works — see docs/DIARY.md on scoped CSS being silently inert when it does not match.

   Still a real tap target at 2.75rem: small NEXT TO a 4rem seat, never small in the hand. Without
   this the Small button is 24px tall, which is half the minimum and the wrong half.

   DO NOT WRITE A COMMENT-CLOSE SEQUENCE INSIDE A COMMENT. The comment that used to stand here
   quoted one while warning against it, which closed itself two lines early and fed its own last
   sentence to the parser as a selector — and CSS error recovery then swallowed the whole rule
   below, block and all. So the buttons this described rendered at the library's default height for
   the entire life of the comment, and nobody noticed, which is precisely what it was warning
   about. Found by measuring a rendered button (chess-0kh), never by reading the file. */
.draw[b-0fpqgvunok]  .draw-button {
    min-height: 2.75rem;
    padding-inline: 1.5rem;
}

.draw-word[b-0fpqgvunok] {
    font-weight: 600;
}

/* Inherits the button's own foreground rather than naming a colour. A reported draw's button is
   Primary — a solid brand fill — and a fixed neutral grey on it came out very nearly invisible. */
.draw-score[b-0fpqgvunok] {
    margin-inline-start: 0.5rem;
    color: inherit;
    opacity: 0.75;
}

.standing[b-0fpqgvunok] {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    margin: 0 0 1rem;
}

.standing-label[b-0fpqgvunok] {
    color: var(--colorNeutralForeground3);
}

.standing-score[b-0fpqgvunok] {
    font-size: 1.75rem;
    font-weight: 700;
}

/* Sits between the seats and the draw option, which is where somebody about to correct a report
   reads it: after the thing they are about to press again, before the smaller thing beside it. */
.prompt[b-0fpqgvunok] {
    margin: 1.25rem 0 0.75rem;
    color: var(--colorNeutralForeground2);
}

/* The one way off this page, and last on it on purpose: everything above is the board, and this is
   what to do when you have finished reading it. Pushed down so a thumb reaching for it cannot catch
   the draw button on the way, and given the same 44px box as any other target here — a link is not
   an excuse for a 20px one. Centred and hugging its words, like the draw: it is an exit, not a
   fourth thing competing with the two seats. */
.onward[b-0fpqgvunok] {
    display: flex;
    justify-content: center;
    margin: 2rem 0 0;
}

.onward a[b-0fpqgvunok] {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    padding: 0 1rem;
    color: var(--colorBrandForegroundLink, var(--colorNeutralForeground1));
    font-size: 1.05rem;
    font-weight: 600;
}
/* /Components/Shared/BoardPlayer.razor.rz.scp.css */
/* The cell in both of its forms — a button while the round can take a result, plain text once it
   cannot. One rule for both so the two cannot drift apart, and so a round closing does not move the
   name half a pixel sideways under the manager's eye.

   Colours come from the FluentUI base theme's design tokens rather than from hex values. Light
   theme only, as everywhere in this app — a settled decision, not an omission. */
.pick[b-h870a19nqh] {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.35rem 0.6rem;
    border: 1px solid transparent;
    border-radius: 0.375rem;
    background: none;
    font: inherit;
    color: inherit;
    text-align: start;
}

/* 44px, the app's own row minimum (see wwwroot/app.css). This grid is used standing up, at the
   front of a hall, on whatever the manager has in their hand — the same thumb that reports from a
   phone at the board, so the same target. */
button.pick[b-h870a19nqh] {
    min-height: var(--row-min-height, 44px);
    border-color: var(--colorNeutralStroke2);
    cursor: pointer;
}

/* Hover belongs to the cell nobody has reported yet, and to nothing else — see the same rule and
   the same reasoning in TablePage.razor.css. A tap latches :hover on, so a hover rule that could
   reach a reported cell would repaint the winner as merely-hovered the instant it was chosen. */
@media (hover: hover) {
    button.pick-open:hover[b-h870a19nqh] {
        background: var(--colorNeutralBackground1Hover);
        border-color: var(--colorNeutralStroke1);
    }
}

/* Drawn rather than left to the browser: the cell has its own border radius, and the grid clips
   data cells (`overflow: hidden`, for the ellipsis on a long name), which trims a default ring. */
button.pick:focus-visible[b-h870a19nqh] {
    outline: 2px solid var(--colorStrokeFocus2, var(--colorNeutralForeground1));
    outline-offset: -1px;
}

/* Who won, before any figure is read. */
.pick-won[b-h870a19nqh] {
    border-color: var(--colorBrandStroke1, var(--colorNeutralForeground1));
    background: var(--colorBrandBackground2, var(--colorNeutralBackground1Selected));
    font-weight: 600;
}

.pick-lost[b-h870a19nqh] {
    opacity: 0.55;
}

.pick-drew[b-h870a19nqh] {
    border-color: var(--colorNeutralStroke1);
    background: var(--colorNeutralBackground3);
}

/* The player's own figure — 1, ½ or 0 — kept in a fixed-width column so the names below each other
   still line up, and so an unreported row does not sit half a character to the left of a reported
   one. Not aria-hidden: it is the scoresheet, not decoration. */
.pick-mark[b-h870a19nqh] {
    flex: 0 0 1.1rem;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.pick-won .pick-mark[b-h870a19nqh] {
    color: var(--colorBrandForeground1, var(--colorNeutralForeground1));
}

/* Names are data and some of them are long. The grid already clips its cells; letting the name wrap
   inside a 44px-minimum row is what keeps a long one readable rather than cut off mid-surname. */
.pick-name[b-h870a19nqh] {
    min-width: 0;
    overflow-wrap: anywhere;
}
/* /Components/Shared/PageHeading.razor.rz.scp.css */
/* Every page's title block. Scoped, because every element here is authored in the .razor above and
   therefore carries the scope attribute — unlike a DataGrid's own cells, which is why row height
   lives in wwwroot/app.css instead. */

.page-heading[b-lkar4jbuag] {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    /* The title and the page's own action end up at opposite ends however wide the window is. */
    justify-content: space-between;
    flex-wrap: wrap;
    width: 100%;
}

/* Takes the row's width rather than its own content's, or the description below wraps against the
   width of the title above it — which on a short title like "Roster" is nothing at all. */
.page-heading-text[b-lkar4jbuag] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 auto;
    min-width: 0;
    /* Children take their own width, not the column's. A flex column stretches them by default,
       which turned the round pages' status badge into a full-width blue bar. */
    align-items: flex-start;
}

/* The browser's default h1 margin is a full line above and below, which on a page that is already
   a 16px stack reads as an unexplained gap. The stack owns the spacing; the heading owns none. */
.page-heading h1[b-lkar4jbuag] {
    margin: 0;
}

/* Capped at a readable measure — a sentence running the full width of a monitor is not read, it is
   skipped. 80 characters, not 68: at 68 the single-sentence descriptions on the tournament and
   password pages broke onto a second line for their last two words. */
.page-heading-description[b-lkar4jbuag] {
    margin: 0;
    color: var(--colorNeutralForeground2);
    max-width: 80ch;
}

/* Nudged down so a button sits on the title's baseline rather than its cap height. */
.page-heading-actions[b-lkar4jbuag] {
    display: flex;
    align-items: center;
    gap: 8px;
    padding-top: 4px;
}
/* /Components/Shared/ProfileEditor.razor.rz.scp.css */
/* The profile form: five short fields and a photo. Shared by the manager's people page and by a
   member's own profile page, which is why these rules live with the component rather than with
   either page — CSS isolation is per component, and the markup moved here. */

/* Two or three fields to a row on a monitor and one to a row on a phone, without a media query
   having to guess where the break is.

   Three of these four declarations exist to keep that promise on a 375px screen, where the form
   was laying three 240px columns out inside a 301px card and clipping two of them:

   • `width: 100%` — FluentStack's inner element is a flex container that does not stretch its
     children, so a grid inside it is sized shrink-to-fit, which for `auto-fit` means max-content:
     every column it could ever want, side by side, however narrow the card is.
   • `min-width: 0` — a flex item's automatic minimum is its content, which would put the overflow
     straight back the moment the first one takes effect.
   • `min(15rem, 100%)` — `minmax(15rem, …)` cannot produce a track narrower than 15rem, so on a
     screen with less than that to spare the single remaining column overflows on its own. This is
     the standard reading of "at least 15rem, unless there is not 15rem". */
.editor-fields[b-t90bq2qqa3] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
    gap: 12px 16px;
    width: 100%;
    min-width: 0;
    max-width: 56rem;
}

/* The photo and its controls side by side, wrapping under each other when there is no room. */
.photo-row[b-t90bq2qqa3] {
    display: flex;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 16px;
}

.photo[b-t90bq2qqa3] {
    width: 96px;
    height: 96px;
    border-radius: var(--borderRadiusMedium);
    /* The browser shrinks a photo to fit a square-ish bound, not to a square, so a portrait taken
       on a phone still arrives taller than it is wide. Trimmed to fit beats squeezed to fit. */
    object-fit: cover;
    border: 1px solid var(--colorNeutralStroke2);
    background: var(--colorNeutralBackground3);
}

/* The picker, the rules and Remove, stacked beside the photo rather than under it. */
.photo-controls[b-t90bq2qqa3] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: flex-start;
}

.photo-empty[b-t90bq2qqa3] {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* A file input is the one control here that is not a Fluent component — see the comment on it in
   the component. Wrapping it in its own label associates the two without an id to keep in step,
   and gives the browser's own button something civilised to sit next to. */
.photo-picker[b-t90bq2qqa3] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.photo-picker-label[b-t90bq2qqa3] {
    font-weight: var(--fontWeightSemibold);
}

/* Framing the photo. Everything below is laid out for a phone first — the club says nine uses in
   ten are one — and widens rather than rearranges on a monitor. */
.photo-editor[b-t90bq2qqa3] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    border: 1px solid var(--colorNeutralStroke2);
    border-radius: var(--borderRadiusMedium);
    background: var(--colorNeutralBackground2);
    max-width: 56rem;
}

/* The line above turns off the `hidden` attribute, and this is what turns it back on.

   `hidden` is honoured by a rule in the browser's own stylesheet, and ANY author rule setting
   `display` beats the whole user-agent sheet whatever its specificity — so a component that is
   hidden by an attribute and laid out by a class is permanently visible unless it says this. It
   happens to work here without it, because FluentUI's default-fuib.css carries
   `[hidden] { display: none !important }`, which is somebody else's stylesheet holding this
   component together. */
.photo-editor[hidden][b-t90bq2qqa3] {
    display: none;
}

.photo-editor-panes[b-t90bq2qqa3] {
    display: flex;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 16px;
}

/* The box IS the crop: what is inside it is what gets stored, at the aspect ratio it gets stored
   at, so there is no frame to read and no part of the picture shown that is about to be thrown
   away.

   `touch-action: none` is the load-bearing line. Without it a drag on a phone scrolls the page and
   a pinch zooms it, and the gesture never reaches the canvas at all — the interaction the whole
   feature is for. 256px so it fits inside a card on a 375px screen without max-width having to
   shrink it, which it will still do on anything narrower. */
.photo-crop[b-t90bq2qqa3] {
    width: 256px;
    height: 256px;
    max-width: 100%;
    touch-action: none;
    cursor: grab;
    border-radius: var(--borderRadiusMedium);
    border: 1px solid var(--colorNeutralStroke1);
    background: var(--colorNeutralBackground3);
}

.photo-crop:active[b-t90bq2qqa3] {
    cursor: grabbing;
}

.photo-editor-previews[b-t90bq2qqa3] {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 12px;
    max-width: 16rem;
}

/* The two real sizes, with the two real corner radii: 96px is the thumbnail on this form and in
   the people list, 144px is the profile page. Not scaled-down copies of a big preview — the point
   of showing them is that they do not lie about how large the face ends up. */
.photo-preview-small[b-t90bq2qqa3] {
    width: 96px;
    height: 96px;
    border-radius: var(--borderRadiusMedium);
    border: 1px solid var(--colorNeutralStroke2);
    background: var(--colorNeutralBackground3);
}

.photo-preview-large[b-t90bq2qqa3] {
    width: 144px;
    height: 144px;
    border-radius: var(--borderRadiusLarge);
    border: 1px solid var(--colorNeutralStroke2);
    background: var(--colorNeutralBackground3);
}

.photo-zoom[b-t90bq2qqa3] {
    display: flex;
    align-items: center;
    gap: 12px;
    max-width: 24rem;
}

/* Wide enough to be draggable with a thumb, and the input is what takes the leftover width rather
   than the label. */
.photo-zoom input[b-t90bq2qqa3] {
    flex: 1 1 auto;
    min-width: 0;
    touch-action: none;
}

.photo-editor-actions[b-t90bq2qqa3] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
/* /Components/Shared/RowActions.razor.rz.scp.css */
/* The action cell's own row of buttons.

   Scoped rather than global, and that is safe precisely because this <div> is authored here in
   markup: Blazor stamps the scope attribute on it. The grid's own td/th cannot be reached this way
   — they are generated inside the library and carry no scope attribute — which is why row HEIGHT
   lives in wwwroot/app.css and only the buttons live here. */

.row-actions[b-v0fagk8i17] {
    display: flex;
    gap: 4px;
    /* Flush with the right edge of the cell: the action column is the last one and sized to its
       content, so anything else leaves the buttons floating in the middle of nothing. */
    justify-content: flex-end;
    align-items: center;
    /* Wrapping is what turns a two-button cell into a two-line row. It never wraps: the column is
       an `auto` track, so it takes the width its buttons need. */
    white-space: nowrap;
}
