.field { display: grid; gap: var(--pt-space-1); margin-bottom: var(--pt-space-4); }
.field__label { color: var(--pt-text-secondary); font: 700 var(--pt-text-caption) var(--pt-font-body); }
.field__required { margin-left: var(--pt-space-1); color: var(--pt-unavailable-icon); font-size: 11.5px; font-weight: 400; }
.field__required--missing { padding: 2px 5px; border-radius: var(--pt-radius-pill); background: oklch(from var(--pt-danger) l c h / .12); color: var(--pt-danger); font-family: var(--pt-font-mono); font-size: 8px; font-weight: 400; }
.field__control { min-height: 44px; width: 100%; box-sizing: border-box; border: var(--pt-border-card); border-radius: var(--pt-radius-md); background: var(--pt-cream-50); color: var(--pt-ink-900); font: 14px var(--pt-font-body); padding: 9px var(--pt-space-3); }
/* Descriptions run to a few lines: tall enough to read and select them, and the owner may drag it taller. */
textarea.field__control { resize: vertical; line-height: 1.45; }
.field__control:focus { outline: 0; border-color: var(--pt-forest-600); box-shadow: var(--pt-focus-ring); }
.field__help { margin: 0; color: var(--pt-text-meta); font-size: var(--pt-text-caption); }
.field__error { margin: 0; color: var(--pt-danger); font-size: 12.5px; }
.field--error .field__control { border-color: var(--pt-danger); background: var(--pt-danger-surface); box-shadow: 0 0 0 3px oklch(from var(--pt-danger) l c h / .12); }
.field-summary { display: flex; align-items: center; gap: var(--pt-space-2); margin-bottom: var(--pt-space-4); padding: 11px 13px; border: 1px solid oklch(from var(--pt-danger) l c h / .3); border-radius: 9px; background: var(--pt-danger-summary); color: var(--pt-danger); font-size: 12.5px; font-weight: 700; }

.capy-segmented { display: inline-flex; overflow: hidden; border: var(--pt-border-card); border-radius: var(--pt-radius-md); }
.capy-segmented__option { min-height: 40px; border: 0; background: transparent; color: var(--pt-text-muted); font: 800 12.5px var(--pt-font-body); padding: 0 var(--pt-space-3); }
.capy-segmented__option[aria-pressed="true"] { background: var(--pt-forest-700); color: var(--pt-cream-50); }

/* Language picker. Deliberately NOT a .capy-segmented variant: that control is shared by Analytics'
   period tabs, Team's roster tabs and two Settings fields, all with a variable number of
   variable-width options, and a sliding thumb needs exactly two options of equal fixed width. The
   panel language is the only two-way, never-more-than-two choice in the dashboard, so it gets its
   own control instead of bending the shared one out of shape for three other screens.

   --langpicker-option is a local dimension, not a design token — the same precedent
   Settings.razor.css set for its fixed 214px nav column. It appears in three rules (thumb width,
   thumb travel, option width) and the three must agree, which is exactly what a local custom
   property is for. The travel is --pt-dur-swap / --pt-ease-slow: both tokens already exist and were
   declared for precisely this gesture (they are the landing's language toggle timings). */
.capy-langpicker { --langpicker-option: 132px; position: relative; display: inline-flex; padding: 3px; border: var(--pt-border-card); border-radius: var(--pt-radius-md); background: var(--pt-cream-100); }
.capy-langpicker__thumb { position: absolute; top: 3px; left: 3px; width: var(--langpicker-option); height: calc(100% - 6px); border-radius: 5px; background: var(--pt-forest-700); box-shadow: var(--pt-shadow-card); transition: transform var(--pt-dur-swap) var(--pt-ease-slow); }
.capy-langpicker--en .capy-langpicker__thumb { transform: translateX(var(--langpicker-option)); }
.capy-langpicker__option { position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; gap: var(--pt-space-2); width: var(--langpicker-option); min-height: 36px; border: 0; border-radius: 5px; background: transparent; color: var(--pt-text-muted); cursor: pointer; transition: color var(--pt-dur-swap) var(--pt-ease-slow); }
.capy-langpicker__option[aria-pressed="true"] { color: var(--pt-cream-50); }
.capy-langpicker__option:not([aria-pressed="true"]):hover { background: oklch(from var(--pt-forest-700) l c h / .06); color: var(--pt-text-strong); }
/* The control is disabled for the length of the swap, but it must not read as inert: the thumb has
   already travelled to where the user pointed, and dimming the labels would undo that answer. */
.capy-langpicker__option:disabled { cursor: default; }
.capy-langpicker__code { font-family: var(--pt-font-mono); font-size: 9px; letter-spacing: .08em; opacity: .6; }
.capy-langpicker__name { font: 800 12.5px var(--pt-font-body); }
/* Per capy-tokens.css's stated policy — suppress movement, keep colour — declared here beside the
   transform it suppresses rather than globally. */
@media (prefers-reduced-motion: reduce) {
  .capy-langpicker__thumb { transition: none; }
}

.capy-radio-card { display: flex; align-items: center; width: 100%; min-height: 52px; box-sizing: border-box; gap: var(--pt-space-3); padding: var(--pt-space-3); border: 1px solid var(--pt-radio-card-border); border-radius: 10px; background: var(--pt-surface); }
.capy-radio-card:has(input:checked) { border-color: var(--pt-olive-500); background: var(--pt-radio-selected); }
.capy-radio-card input { position: absolute; inline-size: 1px; block-size: 1px; opacity: 0; }
.capy-radio-card__mark { width: 18px; height: 18px; flex: none; box-sizing: border-box; border: 1px solid var(--pt-radio-mark-border); border-radius: 50%; }
.capy-radio-card:has(input:checked) .capy-radio-card__mark { border: 5px solid var(--pt-success); }
.capy-radio-card__body { min-width: 0; }
.capy-radio-card__title { display: block; color: var(--pt-ink-900); font: 700 14px var(--pt-font-display); }
.capy-radio-card__description { display: block; overflow: hidden; color: var(--pt-text-muted); font-size: var(--pt-text-caption); line-height: var(--pt-leading-caption); text-overflow: ellipsis; white-space: nowrap; }
/* A card for a mode the product does not offer yet. Same inert dress as
   .capy-form-action--disabled below -- --pt-cream-100 ground with --pt-text-secondary, which
   clears 4.5:1 where --pt-text-muted would not. The input carries the native `disabled`, so this
   is only the visual half; nothing here is load-bearing for the behaviour. */
.capy-radio-card--unavailable { background: var(--pt-cream-100); cursor: not-allowed; }
.capy-radio-card--unavailable .capy-radio-card__title,
.capy-radio-card--unavailable .capy-radio-card__description { color: var(--pt-text-secondary); }
.capy-radio-card__badge { display: inline-block; margin-left: var(--pt-space-2); padding: 1px var(--pt-space-2); border: var(--pt-border-card); border-radius: var(--pt-radius-pill); background: var(--pt-surface); color: var(--pt-text-secondary); font: 700 var(--pt-text-caption) var(--pt-font-body); vertical-align: middle; }
.capy-toggle { position: relative; width: 46px; height: 27px; flex: none; border: 0; border-radius: var(--pt-radius-pill); background: var(--pt-toggle-off); cursor: pointer; transition: background var(--pt-dur-color) var(--pt-ease-soft); }
.capy-toggle[aria-checked="true"] { background: var(--pt-success); }
.capy-toggle__knob { position: absolute; top: 3px; left: 3px; width: 21px; height: 21px; border-radius: 50%; background: var(--pt-surface); box-shadow: var(--pt-shadow-card); transition: transform var(--pt-dur-return) var(--pt-ease-soft); }
.capy-toggle[aria-checked="true"] .capy-toggle__knob { transform: translateX(19px); }
.capy-stepper { display: inline-flex; align-items: center; gap: var(--pt-space-2); }
.capy-stepper__button { width: 32px; height: 32px; border: var(--pt-border-card); border-radius: var(--pt-radius-sm); background: var(--pt-surface); color: var(--pt-text-strong); }
.capy-stepper__value { min-width: 2ch; text-align: center; font-variant-numeric: tabular-nums; }
.capy-segmented__option:focus-visible, .capy-langpicker__option:focus-visible, .capy-toggle:focus-visible, .capy-stepper__button:focus-visible, .capy-radio-card:has(input:focus-visible) { outline: var(--pt-focus-outline); outline-offset: 2px; }

.capy-form-action { display: inline-flex; align-items: center; justify-content: center; gap: var(--pt-space-1); min-height: var(--pt-action-min-height); box-sizing: border-box; padding: 0 var(--pt-space-3); border: var(--pt-border-card); border-radius: var(--pt-radius-md); background: var(--pt-surface); color: var(--pt-text-secondary); font: 700 var(--pt-text-caption) var(--pt-font-body); text-decoration: none; cursor: pointer; transition: all var(--pt-dur-hover) var(--pt-ease-soft); }
.capy-form-action--primary { border-color: var(--pt-forest-700); background: var(--pt-forest-700); color: var(--pt-cream-50); }
.capy-form-action--danger { color: var(--pt-danger); }
.capy-form-action--warning { border-color: var(--pt-occupied-border); background: var(--pt-occupied-tint); color: var(--pt-occupied-fg); }
.capy-form-action--danger-solid { border-color: var(--pt-danger); background: var(--pt-danger); color: var(--pt-surface); }
/* Text colour is restated per variant at hover: Bootstrap's `a:hover` (0,1,1) outranks the
   variants' resting colour (0,1,0), which turned an <a> action link-blue. The variant rules must
   stay after the plain one. */
.capy-form-action:hover { transform: var(--pt-lift-hover); box-shadow: var(--pt-shadow-card); color: var(--pt-text-secondary); }
.capy-form-action--primary:hover { color: var(--pt-cream-50); }
.capy-form-action--danger:hover { border-color: var(--pt-danger); background: var(--pt-danger-surface); color: var(--pt-danger); }
.capy-form-action--warning:hover { color: var(--pt-occupied-fg); }
.capy-form-action--danger-solid:hover { color: var(--pt-surface); }
.capy-form-action:active { transform: none; box-shadow: none; }
.capy-form-action:focus-visible { outline: none; box-shadow: var(--pt-focus-ring); }
/* Fix round 5 (Tables.razor "Editar salón"): an aria-disabled action stays focusable and
   clickable (native `disabled` drops it from the tab order), so it needs its own visual "inert"
   treatment instead of relying on the browser's disabled rendering. Same tokens/shape as
   WaiterDisplay.razor.css's .alert-card__action--disabled -- reused, not invented. */
/* P15 Task 5 (R20 fix): --pt-unavailable-icon (#A0A89C) on --pt-cream-100 (#F7F1E3) is ~2.17:1,
   which fails WCAG AA (4.5:1) at this label's 700 13px weight/size -- below the large-text
   threshold. The WaiterDisplay precedent this rule was copied from dresses a genuinely inert,
   non-interactive button, which is exempt; "Editar salón" stays fully operable while
   aria-disabled, so that exemption does not apply here. --pt-text-secondary (#4A5A4E) clears
   4.5:1 comfortably -- --pt-neutral (#7C8A80) was tried and still misses at ~3.4:1. */
.capy-form-action--disabled,
.capy-form-action--disabled:hover,
.capy-form-action:disabled,
.capy-form-action:disabled:hover {
    border: var(--pt-border-card);
    background: var(--pt-cream-100);
    color: var(--pt-text-secondary);
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
}

/* The knob is the one transform this sheet animates. Reduced motion keeps the colour change of
   the track — the state still reads — and drops the 19px slide, which is the actual motion.
   The lift on .capy-form-action needs nothing here: --pt-lift-hover resolves to `none` under
   the same query (capy-tokens.css), so every lift call site is covered at the token. */
@media (prefers-reduced-motion: reduce) {
  .capy-toggle__knob { transition: none; }
}

/* ── Row action menu (.capy-rowmenu) ──────────────────────────────────────────────────────────
   One kebab trigger plus a popover, shared by every list row that has more actions than fit
   beside its content: menu sections and dish rows today. It replaces the pattern those two rows
   used before — a cluster of five or six 28px icon buttons revealed on hover, absolutely
   positioned over the row's right edge. In a 280px panel that cluster covered the section name
   outright, and over a selected row its white fill collided with --pt-forest-700.

   The trigger holds its own space at all times, so nothing reflows under the pointer and nothing
   is ever hidden behind a hover the user has to discover. Only its tint changes on hover, which
   is why there is no @media (hover: none) escape hatch here: the control is already visible and
   operable on a touch screen.

   Anatomy is the nav rail's popover (--pt-radius-popover, --pt-shadow-popover, 34px items) at
   this surface's light palette rather than the rail's forest one. */
.capy-rowmenu { position: relative; flex: none; display: flex; }

.capy-rowmenu__trigger {
    display: grid;
    place-items: center;
    width: var(--rowmenu-trigger, 28px);
    height: var(--rowmenu-trigger, 28px);
    flex: none;
    padding: 0;
    border: var(--rowmenu-trigger-border, 0);
    border-radius: var(--pt-radius-sm);
    background: transparent;
    color: var(--pt-text-faint);
    cursor: pointer;
    transition: background var(--pt-dur-quick) var(--pt-ease-enter),
                color var(--pt-dur-quick) var(--pt-ease-enter),
                border-color var(--pt-dur-quick) var(--pt-ease-enter);
}

.capy-rowmenu__trigger:hover,
.capy-rowmenu__trigger[aria-expanded="true"] {
    background: var(--pt-cream-100);
    color: var(--pt-ink-900);
}

.capy-rowmenu__trigger:focus-visible {
    outline: var(--pt-focus-outline);
    outline-offset: 2px;
}

/* The backdrop is what closes the menu on an outside click. Transparent and below the panel,
   above everything else on the page. */
.capy-rowmenu__backdrop { position: fixed; inset: 0; z-index: 40; background: transparent; border: 0; }

.capy-rowmenu__panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 41;
    width: 224px;
    padding: 5px;
    border: 1px solid var(--pt-line-200);
    border-radius: var(--pt-radius-popover);
    background: var(--pt-surface);
    box-shadow: var(--pt-shadow-popover);
    text-align: left;
}

/* Set by primeTableRowMenu (wwwroot/js/app.js) when the panel would run past the bottom of the
   window: it opens above the kebab instead. */
.capy-rowmenu__panel[data-open-up] { top: auto; bottom: calc(100% + 6px); }

.capy-rowmenu__item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    box-sizing: border-box;
    min-height: 34px;
    padding: var(--pt-space-2) 10px;
    border: 0;
    border-radius: var(--pt-radius-md);
    background: transparent;
    color: var(--pt-text-strong);
    font-family: var(--pt-font-body);
    font-size: var(--pt-text-caption);
    font-weight: 700;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background var(--pt-dur-quick) var(--pt-ease-enter),
                color var(--pt-dur-quick) var(--pt-ease-enter);
}

.capy-rowmenu__item > i { flex: none; font-size: 14px; }
.capy-rowmenu__item:hover { background: var(--pt-row-hover); color: var(--pt-ink-900); }

.capy-rowmenu__item:focus-visible {
    outline: var(--pt-focus-outline);
    outline-offset: -2px;
}

.capy-rowmenu__item:disabled,
.capy-rowmenu__item:disabled:hover {
    background: transparent;
    color: var(--pt-text-faint);
    cursor: not-allowed;
}

.capy-rowmenu__item--danger { color: var(--pt-danger); }
.capy-rowmenu__item--danger:hover { background: var(--pt-danger-summary); color: var(--pt-on-danger); }

.capy-rowmenu__sep { display: block; height: 1px; margin: var(--pt-space-1) 6px; background: var(--pt-row-divider); }

/* A file picker rendered as a menu item — "Cambiar foto" on a dish row. The input itself is
   removed from the flow rather than display:none so it stays focusable.

   No ::deep here. This is a GLOBAL stylesheet, where ::deep is not a real selector — it is a
   Blazor scoped-CSS construct rewritten at build time only for a .razor.css file. Written into a
   global sheet it makes the browser discard the whole selector list, which took the plain
   .capy-rowmenu__file rule down with it and rendered the native file input inside the menu. */
.capy-rowmenu__file {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

.capy-rowmenu__item:focus-within {
    outline: var(--pt-focus-outline);
    outline-offset: -2px;
}

/* Touch: menu items grow to the 44px target, the trigger is already at least 28px inside a 46px
   row whose whole surface selects the section.
   pointer: coarse is paired with hover: none deliberately — hover: none alone also matches a
   stylus and some TV browsers, where 38px is correct. The pair is the codebase's single stated
   trigger for touch sizing (capy-tokens.css). */
@media (hover: none) and (pointer: coarse) {
    .capy-rowmenu__item { min-height: var(--pt-action-min-height-touch); }
    .capy-rowmenu__trigger { --rowmenu-trigger: var(--pt-action-min-height-touch); }
    .capy-form-action { min-height: var(--pt-action-min-height-touch); }
    .capy-segmented__option { min-height: var(--pt-action-min-height-touch); }
    .capy-stepper__button { width: var(--pt-action-min-height-touch); height: var(--pt-action-min-height-touch); }
    .capy-toggle { width: 56px; height: var(--pt-action-min-height-touch); }
    .capy-toggle__knob { width: 32px; height: 32px; top: 6px; left: 6px; }
    .capy-toggle[aria-checked="true"] .capy-toggle__knob { transform: translateX(12px); }
    .capy-langpicker__option { min-height: var(--pt-action-min-height-touch); }
}

@media (prefers-reduced-motion: reduce) {
    .capy-rowmenu__trigger, .capy-rowmenu__item { transition: none; }
}
