/* TaskStepRenderer Styles - Shared widget stylesheet.
   Used by operator-platform (Create Task modal request fields, Inbox execution
   modal, template-builder phone-frame preview) AND staff-app (real phone task
   execution). Kept byte-identical in shared/components/ and
   operator-platform/shared/components/ (pinned by task-domain-mirror.test.mjs).

   SCOPE CONTRACT (Wave B): every render path of TaskStepRenderer.js carries the
   .tsr-scope root class (.step-container, the _renderFieldSet wrapper,
   completion feedback, empty state) and EVERY rule in this file is scoped under
   it, so nothing here can leak onto host-app atoms that reuse the same generic
   class names (.input-group, .checkbox-wrapper, .slider-input, ...). The single
   documented exception is .empty-step at the bottom.

   TOKENS: all values below flow from the --tsr-* custom properties declared on
   .tsr-scope. The defaults ARE the canonical staff-phone look (the A3 staff
   palette folded in from the retired staff-app/app.css override block), so this
   file renders standalone with no token file and the builder phone frame stays
   a truthful staff preview. Operator surfaces opt IN to the warm operator skin
   by wrapping the renderer host in .tsr-operator-skin -- that bridge block
   lives at the end of operator-platform/styles/design-tokens.css and re-points
   the --tsr-* tokens at operator design tokens. The builder phone frame
   deliberately never gets the wrapper. */

/* ============================================= */
/* SCOPE ROOT + DESIGN TOKENS                    */
/* ============================================= */

.tsr-scope {
    /* Typography (staff phone scale) */
    --tsr-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --tsr-text-xs:   0.7rem;    /* hints */
    --tsr-text-sm:   0.8rem;    /* descriptions, alerts */
    --tsr-text-md:   0.85rem;   /* option text (radio / checkbox-group), buttons */
    --tsr-text-base: 0.9rem;    /* input fields AND their labels -- same size,
                                   hierarchy from weight (label 500, value 400) */
    --tsr-text-lg:   1rem;      /* step instruction, stepper glyphs */
    --tsr-text-2xl:  1.3rem;    /* completion title */

    /* Brand accent (one green) */
    --tsr-accent:       #16a34a;
    --tsr-accent-hover: #15803d;
    --tsr-accent-press: #14532d;
    --tsr-accent-wash:  #f0fdf4;

    /* Surfaces + wells (warm A3 ground) */
    --tsr-surface:            #ffffff;
    --tsr-surface-raised:     rgba(255, 255, 255, 0.8);
    --tsr-hover:              #f5f4f2;
    --tsr-active:             #f0efed;
    --tsr-well:               #e4e1db;
    --tsr-track:              #e8e7e4;
    --tsr-secondary-bg:       #e8e7e4;
    --tsr-secondary-bg-hover: #dfddd8;

    /* Borders (warm) */
    --tsr-border:       #d8d6d2;  /* option cards, checkbox box, switch off-track */
    --tsr-border-field: #f0efed;  /* input + stepper chrome (near-invisible A3 field border) */
    --tsr-border-hover: #a8a6a0;
    --tsr-border-faint: rgba(0, 0, 0, 0.1);

    /* Text (warm ink) */
    --tsr-text:           #1a1a1a;
    --tsr-text-secondary: #83817b;
    --tsr-text-faint:     #a8a6a0;
    --tsr-text-inverse:   #ffffff;

    /* Status */
    --tsr-danger:        #ef4444;
    --tsr-danger-strong: #dc2626;
    --tsr-danger-text:   #991b1b;
    --tsr-danger-wash:   #fef2f2;
    --tsr-danger-tint:   #fee2e2;
    --tsr-danger-line:   #fca5a5;
    --tsr-warning:       #f59e0b;
    --tsr-warning-text:  #b45309;
    --tsr-warning-tint:  #fef3c7;
    --tsr-warning-wash:  rgba(234, 179, 8, 0.06);
    --tsr-warning-line:  rgba(234, 179, 8, 0.2);
    --tsr-info-tint:     #e0e7ff;
    --tsr-info-text:     #3730a3;
    --tsr-scrim:         rgba(0, 0, 0, 0.6);
    --tsr-scrim-strong:  rgba(0, 0, 0, 0.8);

    /* Spacing (4px scale; s-0 is the micro rung for chip padding) */
    --tsr-s-0: 2px;
    --tsr-s-1: 4px;
    --tsr-s-2: 8px;
    --tsr-s-3: 12px;
    --tsr-s-4: 16px;
    --tsr-s-5: 20px;
    --tsr-s-6: 24px;

    /* Control geometry */
    --tsr-control-pad-y:   8px;   /* vertical padding of every control row */
    --tsr-control-pad-x:   10px;  /* horizontal padding of every control row */
    --tsr-touch-target:    44px;  /* min-height of boolean rows + buttons */
    --tsr-textarea-min-h:  72px;
    --tsr-stepper-w:       40px;
    --tsr-radio-size:      18px;
    --tsr-checkbox-size:   20px;
    --tsr-switch-w:        40px;
    --tsr-switch-h:        22px;
    --tsr-switch-thumb:    18px;
    --tsr-slider-thumb:    20px;
    --tsr-slider-value-w:  36px;
    --tsr-chevron-pad:     32px;  /* right padding clearing the select chevron */
    --tsr-completion-icon: 64px;
    --tsr-hero-pad-y:      30px;
    --tsr-photo-max-h:     200px;
    --tsr-photo-remove:    32px;

    /* Borders + radii (A3 ramp: fields 6, buttons/cards 10) */
    --tsr-radius-sm:   6px;
    --tsr-radius-md:   10px;
    --tsr-radius-lg:   12px;
    --tsr-radius-pill: 9999px;
    --tsr-radius-full: 50%;

    /* Shadows + focus */
    --tsr-shadow-focus: 0 0 0 3px rgba(22, 163, 74, 0.18);
    --tsr-shadow-sm:    0 1px 2px rgba(0, 0, 0, 0.05);
    --tsr-shadow-thumb: 0 1px 3px rgba(0, 0, 0, 0.15);

    /* Motion */
    --tsr-dur-fast: 0.15s;
    --tsr-dur-base: 0.3s;
    --tsr-dur-slow: 0.6s;

    font-family: var(--tsr-font);
}

/* Form controls do not inherit font by default. */
.tsr-scope input,
.tsr-scope select,
.tsr-scope textarea,
.tsr-scope button {
    font-family: var(--tsr-font);
}

/* ============================================= */
/* RENDER-PATH ROOTS                             */
/* ============================================= */

.tsr-scope.step-container {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-3);
    max-width: 100%;
}

/* Fire-time request fields (Create Task modal renders widgets via
   _renderFieldSet, outside any .step-container). Same column stack. */
.tsr-scope.tsr-fieldset {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-3);
}

/* Step header */
.tsr-scope .step-header {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-1);
}

/* 600, not 700: this is the step heading, and 600 is what every other heading
   in the sheet uses (.task-title, .alert-title, .step-btn). 700 at 16px on a
   phone reads as shouting, and it reads worse still when the authored
   instruction is a sentence rather than a short imperative. */
.tsr-scope .step-instruction {
    font-size: var(--tsr-text-lg);
    font-weight: 600;
    color: var(--tsr-text);
    line-height: 1.3;
}

.tsr-scope .step-description {
    font-size: var(--tsr-text-sm);
    color: var(--tsr-text-secondary);
    line-height: 1.5;
}

/* ============================================= */
/* INPUT FIELDS -- common scaffolding            */
/* ============================================= */

.tsr-scope .input-group {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-1);
}

/* Value-widget row contract -- label LEFT, control RIGHT on one line.
   Same declarations as the boolean row contract further down
   (.switch-wrapper/.checkbox-wrapper): switch and checkbox already read
   this way, so the single-control value widgets now match them instead of
   stacking a full-width field under a label on a surface with room to
   spare. The renderer opts a widget in with .input-group-row; the widgets
   that genuinely need the full width (textarea, radio, checkbox-group,
   segmented, slider) keep the stack by not carrying it.

   Scoped to .step-container on purpose: the Create Task modal renders the
   same widgets through _renderFieldSet into .tsr-fieldset, which stays a
   stack. Corrective-action fields inside a threshold alert are separate
   markup and also stay stacked -- they sit in a narrower well. */
.tsr-scope.step-container .input-group-row {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--tsr-s-1) var(--tsr-s-3);
    min-height: var(--tsr-touch-target);
}

.tsr-scope.step-container .input-group-row > .input-label {
    flex: 1 1 auto;
    min-width: 0;
}

/* Half the row, so the control is sized to the reading rather than to the
   screen. .number-stepper is the bounded-number wrapper, not an .input-field. */
.tsr-scope.step-container .input-group-row > .input-field,
.tsr-scope.step-container .input-group-row > .number-stepper {
    flex: 0 0 50%;
    max-width: 50%;
}

/* The band hint is a third child. Wrap it onto its own line under the
   control it describes rather than letting it share the label column. */
.tsr-scope.step-container .input-group-row > .input-hint {
    flex: 1 0 100%;
    text-align: right;
}

/* A label sits at the SAME size as the value it names; the hierarchy between
   them is weight, not size. It used to be --tsr-text-sm, a rung BELOW the
   field, so on the phone the answer shouted louder than the question and the
   label was the smallest content text on the step -- smaller even than the
   description explaining it. On the operator skin --tsr-text-base bridges to
   --text-sm, which is exactly the house .form-label size, so this one rule
   lands correctly on both surfaces. */
.tsr-scope .input-label {
    font-size: var(--tsr-text-base);
    font-weight: 500;
    color: var(--tsr-text);
    line-height: 1.4;
}

/* Phase 7 P5: red asterisk after the label text on required widgets. The
   renderer appends <span class="input-label-required">*</span> when
   field.required === true; this rule paints it. aria-hidden=true on the
   span; the real screen-reader signal is the input's required attribute. */
.tsr-scope .input-label-required {
    color: var(--tsr-danger);
    margin-left: var(--tsr-s-1);
    font-weight: 700;
}

.tsr-scope .input-field {
    padding: var(--tsr-control-pad-y) var(--tsr-control-pad-x);
    font-size: var(--tsr-text-base);
    color: var(--tsr-text);
    background: var(--tsr-surface);
    border: 1.5px solid var(--tsr-border-field);
    border-radius: var(--tsr-radius-sm);
    box-sizing: border-box;
    transition: border-color var(--tsr-dur-fast), box-shadow var(--tsr-dur-fast);
}

.tsr-scope .input-field::placeholder {
    color: var(--tsr-text-faint);
}

.tsr-scope .input-field:hover {
    border-color: var(--tsr-border-hover);
}

.tsr-scope .input-field:focus {
    outline: none;
    border-color: var(--tsr-accent);
    box-shadow: var(--tsr-shadow-focus);
}

.tsr-scope .input-field.invalid {
    border-color: var(--tsr-danger);
    background: var(--tsr-danger-wash);
}

.tsr-scope .input-field.out-of-range {
    border-color: var(--tsr-warning);
    background: var(--tsr-warning-wash);
    color: var(--tsr-warning-text);
}

/* Past the OUTER limit when the author declared a tolerance band (TLP-907).
   Its own class rather than a restyled .out-of-range, so a field whose author
   never opted in keeps painting exactly the amber it painted before. Like
   .out-of-range and unlike .invalid, this NEVER blocks completion -- the
   reading is recorded, and it is the reading the round exists to catch. */
.tsr-scope .input-field.out-of-limit {
    border-color: var(--tsr-danger);
    background: var(--tsr-danger-wash);
    color: var(--tsr-danger-text);
}

.tsr-scope .input-hint {
    font-size: var(--tsr-text-xs);
    color: var(--tsr-text-secondary);
    line-height: 1.4;
}

/* IN the acceptable band -- the only positive state on a step (TLP-907).
   Deliberately the hint alone, never the field: --tsr-accent is the :focus
   border above, so a green input would read as "the cursor is here" rather
   than "this reading is good", and a tint on every correct value makes the
   normal case the loudest thing on a twelve-reading round. */
.tsr-scope .input-hint.in-range {
    color: var(--tsr-accent);
    font-weight: 600;
}

/* Out of the acceptable band. WARNING, not danger: .invalid above means
   "required and empty, you cannot continue"; this value IS recorded -- the
   reading was simply outside min/max, which is exactly what the round is
   looking for. Never blocks completion. */
.tsr-scope .input-hint.out-of-range {
    color: var(--tsr-warning-text);
    font-weight: 600;
}

/* Past the outer limit. Same rule as .input-field.out-of-limit above. */
.tsr-scope .input-hint.out-of-limit {
    color: var(--tsr-danger-text);
    font-weight: 600;
}

/* A reading is a VALUE: it sits at the field size like every other value, and
   is distinguished from the label beside it by nothing more than alignment and
   tabular figures. It used to be 1.1rem/600 -- the loudest thing on the step,
   louder than the heading -- on the theory that a readout should be glanceable.
   On a phone card surrounded by 14.4px text it just read as shouting. */
.tsr-scope .number-input {
    font-variant-numeric: tabular-nums;
    text-align: left;
    font-weight: 500;
    font-size: var(--tsr-text-base);
}

/* Textarea */
.tsr-scope .textarea-field {
    resize: vertical;
    min-height: var(--tsr-textarea-min-h);
    line-height: 1.5;
}

/* Time / date inputs share input-field shape. (JS emits class date-input;
   the historical .date-field selector was dead and is retired.) */
.tsr-scope .time-field,
.tsr-scope .date-input {
    font-variant-numeric: tabular-nums;
}

/* Native select with custom chevron. The stroke colour is baked into the
   data-URI (#83817b url-encoded, = --tsr-text-secondary) because url()
   strings cannot read custom properties -- the one colour in this file a
   skin cannot re-point. */
.tsr-scope .select-field {
    cursor: pointer;
    appearance: none;
    background-image: url('data:image/svg+xml;charset=UTF-8,<svg width="10" height="6" viewBox="0 0 10 6" xmlns="http://www.w3.org/2000/svg"><path d="M1 1L5 5L9 1" stroke="%2383817b" stroke-width="1.5" stroke-linecap="round" fill="none"/></svg>');
    background-repeat: no-repeat;
    background-position: right var(--tsr-control-pad-x) center;
    padding-right: var(--tsr-chevron-pad);
}

/* ============================================= */
/* NUMBER STEPPER                                */
/* ============================================= */

.tsr-scope .number-stepper {
    display: flex;
    align-items: stretch;
    gap: 0;
}

.tsr-scope .number-stepper .number-input {
    flex: 1;
    min-width: 0;
    text-align: center;
    font-weight: 500;
    border-radius: 0;
    border-left: none;
    border-right: none;
    -moz-appearance: textfield;
}

.tsr-scope .number-stepper .number-input::-webkit-inner-spin-button,
.tsr-scope .number-stepper .number-input::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.tsr-scope .stepper-btn {
    width: var(--tsr-stepper-w);
    border: 1.5px solid var(--tsr-border-field);
    background: var(--tsr-surface);
    color: var(--tsr-text);
    /* Chrome, not content. These were 17.6px/700 -- heavier than the step
       heading -- for two glyphs that only need to look tappable. */
    font-size: var(--tsr-text-lg);
    font-weight: 500;
    cursor: pointer;
    transition: background var(--tsr-dur-fast), border-color var(--tsr-dur-fast);
    -webkit-tap-highlight-color: transparent;
}

.tsr-scope .stepper-btn:first-of-type {
    border-top-left-radius: var(--tsr-radius-sm);
    border-bottom-left-radius: var(--tsr-radius-sm);
    border-right: none;
}

.tsr-scope .stepper-btn:last-of-type {
    border-top-right-radius: var(--tsr-radius-sm);
    border-bottom-right-radius: var(--tsr-radius-sm);
    border-left: none;
}

.tsr-scope .stepper-btn:hover {
    background: var(--tsr-hover);
    border-color: var(--tsr-border-hover);
}

.tsr-scope .stepper-btn:active {
    background: var(--tsr-active);
}

/* The stepper's input carries no left/right border -- the flanking buttons
   own those edges -- so tinting the input alone would paint two orphaned
   hairlines. Carry the warning across all three so the control reads as one
   out-of-band field. Matches the :has() usage on .radio-option above. */
.tsr-scope .number-stepper:has(.number-input.out-of-range) .stepper-btn {
    border-color: var(--tsr-warning);
}

.tsr-scope .number-stepper:has(.number-input.out-of-limit) .stepper-btn {
    border-color: var(--tsr-danger);
}

/* ============================================= */
/* RADIO BUTTONS                                 */
/* ============================================= */

.tsr-scope .radio-group {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-2);
}

/* Bordered option cards; padding matches .input-field rows. */
.tsr-scope .radio-option {
    display: flex;
    align-items: center;
    padding: var(--tsr-control-pad-y) var(--tsr-control-pad-x);
    border: 1px solid var(--tsr-border);
    border-radius: var(--tsr-radius-sm);
    background: var(--tsr-surface);
    cursor: pointer;
    transition: border-color var(--tsr-dur-fast), background var(--tsr-dur-fast);
}

.tsr-scope .radio-option:hover {
    border-color: var(--tsr-border-hover);
    background: var(--tsr-hover);
}

.tsr-scope .radio-option input[type="radio"] {
    margin: 0 var(--tsr-control-pad-x) 0 0;
    width: var(--tsr-radio-size);
    height: var(--tsr-radio-size);
    accent-color: var(--tsr-accent);
    cursor: pointer;
}

.tsr-scope .radio-option:has(input:checked) {
    border-color: var(--tsr-accent);
    background: var(--tsr-accent-wash);
}

.tsr-scope .radio-option input[type="radio"]:checked ~ .radio-label {
    font-weight: 600;
    color: var(--tsr-text);
}

/* Color variants -- semantic radio choices (Pass/Fail etc.) */
.tsr-scope .radio-option.radio-success:has(input:checked) {
    border-color: var(--tsr-accent);
    background: var(--tsr-accent-wash);
}

.tsr-scope .radio-option.radio-danger:has(input:checked) {
    border-color: var(--tsr-danger);
    background: var(--tsr-danger-wash);
}

.tsr-scope .radio-option.radio-warning:has(input:checked) {
    border-color: var(--tsr-warning);
    background: var(--tsr-warning-tint);
}

.tsr-scope .radio-label {
    flex: 1;
    font-size: var(--tsr-text-md);
    font-weight: 400;
    color: var(--tsr-text);
    line-height: 1.4;
}

/* ============================================= */
/* SEGMENTED CONTROL                             */
/* ============================================= */

.tsr-scope .segmented-control {
    display: inline-flex;
    width: 100%;
    background: var(--tsr-well);
    border-radius: var(--tsr-radius-pill);
    padding: 3px; /* pill inset, derived from the track height */
}

.tsr-scope .segmented-control-btn {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--tsr-s-2) var(--tsr-s-4);
    border: none;
    border-radius: var(--tsr-radius-pill);
    background: transparent;
    font-size: var(--tsr-text-md);
    font-weight: 500;
    color: var(--tsr-text-secondary);
    cursor: pointer;
    white-space: nowrap;
    transition: color var(--tsr-dur-fast), background var(--tsr-dur-fast);
    -webkit-tap-highlight-color: transparent;
}

.tsr-scope .segmented-control-btn:hover {
    color: var(--tsr-text);
}

.tsr-scope .segmented-control-btn-active {
    background: var(--tsr-surface);
    color: var(--tsr-text);
    box-shadow: var(--tsr-shadow-sm);
}

.tsr-scope .segmented-control-btn:disabled {
    cursor: not-allowed;
    opacity: 0.5;
}

/* ============================================= */
/* COMBOBOX (datalist-based)                     */
/* ============================================= */
/* .combobox-input also carries .input-field so it inherits the standard
   input styling; the chevron mirrors .select-field for a consistent
   dropdown affordance. */

.tsr-scope .input-field.combobox-input {
    background-image: url('data:image/svg+xml;charset=UTF-8,<svg width="10" height="6" viewBox="0 0 10 6" xmlns="http://www.w3.org/2000/svg"><path d="M1 1L5 5L9 1" stroke="%2383817b" stroke-width="1.5" stroke-linecap="round" fill="none"/></svg>');
    background-repeat: no-repeat;
    background-position: right var(--tsr-control-pad-x) center;
    padding-right: var(--tsr-chevron-pad);
}

/* ============================================= */
/* SLIDER                                        */
/* ============================================= */

.tsr-scope .slider-wrapper {
    display: flex;
    align-items: center;
    gap: var(--tsr-s-3);
}

.tsr-scope .slider-input {
    flex: 1;
    -webkit-appearance: none;
    appearance: none;
    height: 6px;
    background: var(--tsr-track);
    border-radius: 3px;
    outline: none;
    cursor: pointer;
}

.tsr-scope .slider-input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: var(--tsr-slider-thumb);
    height: var(--tsr-slider-thumb);
    border-radius: var(--tsr-radius-full);
    background: var(--tsr-accent);
    border: 2px solid var(--tsr-surface);
    box-shadow: var(--tsr-shadow-thumb);
    cursor: pointer;
    transition: transform var(--tsr-dur-fast);
}

.tsr-scope .slider-input::-webkit-slider-thumb:hover {
    transform: scale(1.1);
}

.tsr-scope .slider-input::-moz-range-thumb {
    width: var(--tsr-slider-thumb);
    height: var(--tsr-slider-thumb);
    border-radius: var(--tsr-radius-full);
    background: var(--tsr-accent);
    border: 2px solid var(--tsr-surface);
    box-shadow: var(--tsr-shadow-thumb);
    cursor: pointer;
}

.tsr-scope .slider-value {
    min-width: var(--tsr-slider-value-w);
    padding: var(--tsr-s-0) var(--tsr-s-2);
    background: var(--tsr-well);
    border-radius: var(--tsr-radius-sm);
    font-size: var(--tsr-text-md);
    font-weight: 500;
    color: var(--tsr-text);
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* ============================================= */
/* BOOLEAN ROWS (switch + single checkbox)       */
/* One contract: label text LEFT, control RIGHT, */
/* 44px row. The value widgets now share it.     */
/* ============================================= */

/* A boolean that IS the widget carries a FIELD label, so it takes the field
   label's size and weight -- otherwise the row contract lines two kinds of
   label up in one column at two different sizes and weights (13.6/400 beside
   14.4/500), which is the raggedness the row layout exposed. Group ITEMS keep
   the lighter option style: they are choices inside a widget, not the widget's
   name. Same `>` split as the padding rule below. */
.tsr-scope .input-group > .switch-wrapper .switch-label,
.tsr-scope .input-group > .checkbox-wrapper .checkbox-label-text {
    font-size: var(--tsr-text-base);
    font-weight: 500;
}

.tsr-scope .switch-wrapper,
.tsr-scope .checkbox-wrapper {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    gap: var(--tsr-s-3);
    min-height: var(--tsr-touch-target);
    padding: 0 var(--tsr-control-pad-x);
    box-sizing: border-box;
    margin: 0;
    cursor: pointer;
    position: relative;
    -webkit-tap-highlight-color: transparent;
}

/* A boolean that IS the widget sits flush with the group edge, like every
   other row. The --tsr-control-pad-x inset above lined the label up with the
   inner text of a stacked full-width input; with .input-group-row the value
   labels sit outside their controls, in a column at the group edge, so the
   inset now reads as one label 10px out of line. Group ITEMS keep it -- a
   checkbox-group is a list inside the widget, not the widget itself. */
.tsr-scope .input-group > .switch-wrapper,
.tsr-scope .input-group > .checkbox-wrapper {
    padding: 0;
}

/* Hidden real inputs (the custom track/box is the visual) */
.tsr-scope .switch-input,
.tsr-scope .checkbox-input {
    position: absolute;
    opacity: 0;
    width: auto;
    height: auto;
    pointer-events: none;
    margin: 0;
}

/* Label text -- left side, takes the remaining width */
.tsr-scope .switch-label,
.tsr-scope .checkbox-label {
    flex: 1 1 auto;
    display: block;
    min-width: 0;
    overflow: hidden;
    margin: 0;
    font-size: var(--tsr-text-md);
    font-weight: 400;
    color: var(--tsr-text);
    line-height: 1.4;
}

.tsr-scope .checkbox-label-text {
    display: block;
    font-size: var(--tsr-text-md);
    font-weight: 400;
    color: var(--tsr-text);
    line-height: 1.4;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Switch control -- right side */
.tsr-scope .switch-track {
    position: relative;
    display: inline-block;
    width: var(--tsr-switch-w);
    height: var(--tsr-switch-h);
    background: var(--tsr-border);
    border: none;
    border-radius: var(--tsr-radius-pill);
    transition: background var(--tsr-dur-fast);
    flex-shrink: 0;
    margin: 0;
}

/* Thumb geometry: 2px inset inside the track; travel = track width minus
   thumb minus both insets. */
.tsr-scope .switch-thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: var(--tsr-switch-thumb);
    height: var(--tsr-switch-thumb);
    background: var(--tsr-surface);
    border-radius: var(--tsr-radius-full);
    box-shadow: var(--tsr-shadow-thumb);
    transform: translateX(0);
    transition: transform var(--tsr-dur-fast);
}

.tsr-scope .switch-input:checked ~ .switch-track {
    background: var(--tsr-accent);
}

.tsr-scope .switch-input:checked ~ .switch-track .switch-thumb {
    transform: translateX(calc(var(--tsr-switch-w) - var(--tsr-switch-thumb) - 4px));
}

/* Checkbox control -- right side */
.tsr-scope .checkbox-custom {
    display: inline-block;
    width: var(--tsr-checkbox-size);
    height: var(--tsr-checkbox-size);
    border: 1px solid var(--tsr-border);
    border-radius: var(--tsr-radius-sm);
    background: var(--tsr-surface);
    flex-shrink: 0;
    position: relative;
    margin: 0;
    transition: background var(--tsr-dur-fast), border-color var(--tsr-dur-fast);
}

.tsr-scope .checkbox-input:checked ~ .checkbox-custom {
    background: var(--tsr-accent);
    border-color: var(--tsr-accent);
}

/* Tick geometry derived from the 20px box (--tsr-checkbox-size). */
.tsr-scope .checkbox-input:checked ~ .checkbox-custom::after {
    content: "";
    display: block;
    position: absolute;
    top: 3px;
    left: 6px;
    width: 5px;
    height: 9px;
    border: solid var(--tsr-text-inverse);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
    margin: 0;
}

/* ============================================= */
/* CHECKBOX GROUP (multi-select)                 */
/* ============================================= */

.tsr-scope .checkbox-group {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-2);
}

.tsr-scope .checkbox-group-items {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-2);
}

/* ============================================= */
/* THRESHOLD ALERTS                              */
/* ============================================= */

/* Stable host so a breach can re-paint the alerts alone instead of the whole
   step (TLP-613). It must stay in the DOM even with no alerts, so collapse it
   when empty -- .step-container is a flex column with a gap, and an empty box
   would otherwise show as a phantom gap under the inputs. */
.tsr-scope [data-threshold-alerts]:empty {
    display: none;
}

/* Full 1px severity border + tinted background (house rule: no left-accent
   borders). */
.tsr-scope .threshold-alert {
    margin: var(--tsr-s-4) 0;
    padding: var(--tsr-s-4);
    border-radius: var(--tsr-radius-md);
    border: 1px solid transparent;
    animation: tsr-slide-in var(--tsr-dur-base) ease;
}

@keyframes tsr-slide-in {
    from { opacity: 0; transform: translateY(-10px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* The banner's class is built from the RULE's severity, so the styled set has
   to be the severity set -- info | warning | error | critical, plus the seeded
   corpus's 'major' and the legacy 'high'. It was not: 'error' and 'major' both
   render a banner the judge correctly Fails, and both arrived here unstyled --
   a transparent box with no border, for the worst readings on the round.
   'error' is not hypothetical; it is offered in the Inspector's own Severity
   dropdown (RequestTaskTemplatesModel.getSeverityOptions).

   Grouped by the VERDICT each severity produces, which is what the staffer
   needs to read off the colour: statusForSeverity maps info -> Pass,
   warning -> Warning, and everything else -> Fail. */
.tsr-scope .threshold-alert.alert-info {
    background: var(--tsr-info-tint);
    border-color: var(--tsr-info-text);
}

.tsr-scope .threshold-alert.alert-warning {
    background: var(--tsr-warning-tint);
    border-color: var(--tsr-warning);
}

.tsr-scope .threshold-alert.alert-high,
.tsr-scope .threshold-alert.alert-major,
.tsr-scope .threshold-alert.alert-error,
.tsr-scope .threshold-alert.alert-critical {
    background: var(--tsr-danger-tint);
    border-color: var(--tsr-danger);
}

.tsr-scope .alert-header {
    display: flex;
    align-items: center;
    gap: var(--tsr-s-2);
    margin-bottom: var(--tsr-s-2);
}

.tsr-scope .alert-icon {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    margin: 0;
    font-size: var(--tsr-text-lg);
}

.tsr-scope .alert-title {
    font-weight: 600;
    font-size: var(--tsr-text-sm);
    color: var(--tsr-danger-text);
    margin: 0;
}

.tsr-scope .alert-body {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-3);
}

.tsr-scope .alert-message {
    font-size: var(--tsr-text-sm);
    line-height: 1.5;
    color: var(--tsr-warning-text);
}

/* The corrective-task PREVIEW card and its badges used to live here -- the
   .alert-tasks / .corrective-task-* / .task-* / .steps-* run. It rendered from
   `conditionalTasks` on a threshold rule, which TLP-365 DELETED rather than
   wired: a breach now mints server-side from the control
   (lambda/operator-staff-api/lib/mint-corrective.js). The JS went with that card
   and these ~110 lines were left behind, matching nothing.
   Retirement guarded in operator-platform/__tests__/QADomainModels.test.mjs.
   (.dept-badge / .priority-badge elsewhere in the platform are unrelated -- they
   were never inside .tsr-scope.) */

/* ============================================= */
/* CORRECTIVE ACTION FIELDS (threshold breach)   */
/* ============================================= */

.tsr-scope .corrective-action-fields {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-3);
    margin-top: var(--tsr-s-3);
    padding: var(--tsr-s-3);
    background: var(--tsr-warning-wash);
    border-radius: var(--tsr-radius-md);
    border: 1px solid var(--tsr-warning-line);
}

/* ============================================= */
/* NAVIGATION BUTTONS                            */
/* ============================================= */

.tsr-scope .step-actions {
    display: flex;
    gap: var(--tsr-s-3);
    margin-top: var(--tsr-s-2);
}

.tsr-scope .step-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--tsr-s-2);
    padding: var(--tsr-s-2) var(--tsr-s-5);
    min-height: var(--tsr-touch-target);
    font-size: var(--tsr-text-md);
    font-weight: 600;
    border: 1px solid transparent;
    border-radius: var(--tsr-radius-md);
    cursor: pointer;
    transition: background var(--tsr-dur-fast), border-color var(--tsr-dur-fast), color var(--tsr-dur-fast);
}

.tsr-scope .step-btn svg {
    flex-shrink: 0;
}

.tsr-scope .step-btn-primary {
    background: var(--tsr-accent);
    color: var(--tsr-text-inverse);
    border-color: var(--tsr-accent);
}

.tsr-scope .step-btn-primary:hover:not(:disabled) {
    background: var(--tsr-accent-hover);
    border-color: var(--tsr-accent-hover);
}

.tsr-scope .step-btn-primary:active:not(:disabled) {
    background: var(--tsr-accent-press);
}

.tsr-scope .step-btn-secondary {
    background: var(--tsr-secondary-bg);
    color: var(--tsr-text);
    border-color: var(--tsr-secondary-bg);
}

.tsr-scope .step-btn-secondary:hover:not(:disabled) {
    background: var(--tsr-secondary-bg-hover);
    border-color: var(--tsr-secondary-bg-hover);
}

.tsr-scope .step-btn:disabled,
.tsr-scope .step-btn.disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

/* ============================================= */
/* COMPLETION FEEDBACK                           */
/* ============================================= */

.tsr-scope.completion-feedback {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: var(--tsr-hero-pad-y) var(--tsr-s-4);
}

/* CSS-drawn check inside a green disc (ASCII policy: no emoji glyphs). */
.tsr-scope .completion-icon {
    width: var(--tsr-completion-icon);
    height: var(--tsr-completion-icon);
    border-radius: var(--tsr-radius-full);
    background: var(--tsr-accent);
    position: relative;
    margin-bottom: var(--tsr-s-5);
    animation: tsr-bounce-in var(--tsr-dur-slow) ease;
}

/* Check geometry derived from the 64px disc: a 14x26 border-L rotated 45deg,
   nudged above centre so the glyph reads optically centred. */
.tsr-scope .completion-icon::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 14px;
    height: 26px;
    border: solid var(--tsr-text-inverse);
    border-width: 0 4px 4px 0;
    transform: translate(-50%, -60%) rotate(45deg);
}

@keyframes tsr-bounce-in {
    0%   { opacity: 0; transform: scale(0.3); }
    50%  { transform: scale(1.05); }
    100% { opacity: 1; transform: scale(1); }
}

.tsr-scope .completion-title {
    font-size: var(--tsr-text-2xl);
    font-weight: 700;
    color: var(--tsr-accent);
    margin-bottom: var(--tsr-s-3);
}

.tsr-scope .completion-message {
    font-size: var(--tsr-text-base);
    color: var(--tsr-text-secondary);
    line-height: 1.6;
    margin-bottom: var(--tsr-s-6);
}

.tsr-scope .completion-note {
    color: var(--tsr-text-secondary);
    font-size: var(--tsr-text-sm);
}

/* ============================================= */
/* VALIDATION ALERTS                             */
/* ============================================= */

.tsr-scope .validation-alert {
    display: flex;
    align-items: center;
    gap: var(--tsr-s-2);
    padding: var(--tsr-s-2) var(--tsr-s-3);
    background: var(--tsr-danger-tint);
    border: 1px solid var(--tsr-danger-line);
    border-radius: var(--tsr-radius-sm);
    color: var(--tsr-danger-text);
    font-size: var(--tsr-text-sm);
    margin-bottom: var(--tsr-s-4);
    animation: tsr-shake var(--tsr-dur-base) ease;
}

@keyframes tsr-shake {
    0%, 100% { transform: translateX(0); }
    25%      { transform: translateX(-10px); }
    75%      { transform: translateX(10px); }
}

/* ============================================= */
/* PHOTO CAPTURE (step.photoRequired)            */
/* ============================================= */

.tsr-scope .step-photo-section {
    display: flex;
    flex-direction: column;
    gap: var(--tsr-s-2);
}

.tsr-scope .step-photo-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--tsr-s-2);
    min-height: var(--tsr-touch-target);
    padding: var(--tsr-s-3) var(--tsr-s-4);
    border: 2px dashed var(--tsr-border);
    border-radius: var(--tsr-radius-md);
    background: var(--tsr-surface);
    color: var(--tsr-text);
    font-size: var(--tsr-text-sm);
    font-weight: 500;
    cursor: pointer;
    transition: border-color var(--tsr-dur-fast), background var(--tsr-dur-fast), color var(--tsr-dur-fast);
}

.tsr-scope .step-photo-btn:hover {
    border-color: var(--tsr-accent);
    background: var(--tsr-accent-wash);
    color: var(--tsr-accent-hover);
}

.tsr-scope .step-photo-btn svg {
    stroke: currentColor;
    flex-shrink: 0;
}

.tsr-scope .step-photo-thumb {
    position: relative;
    border-radius: var(--tsr-radius-md);
    overflow: hidden;
    background: var(--tsr-well);
}

.tsr-scope .step-photo-thumb img {
    display: block;
    width: 100%;
    max-height: var(--tsr-photo-max-h);
    object-fit: cover;
}

.tsr-scope .step-photo-remove {
    position: absolute;
    top: var(--tsr-s-2);
    right: var(--tsr-s-2);
    width: var(--tsr-photo-remove);
    height: var(--tsr-photo-remove);
    border-radius: var(--tsr-radius-full);
    border: none;
    background: var(--tsr-scrim);
    color: var(--tsr-text-inverse);
    font-size: var(--tsr-text-lg);
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

.tsr-scope .step-photo-remove:hover {
    background: var(--tsr-scrim-strong);
}

/* ============================================= */
/* FOCUS -- one visible keyboard ring everywhere */
/* ============================================= */

.tsr-scope .stepper-btn:focus-visible,
.tsr-scope .segmented-control-btn:focus-visible,
.tsr-scope .step-btn:focus-visible,
.tsr-scope .step-photo-btn:focus-visible,
.tsr-scope .step-photo-remove:focus-visible,
.tsr-scope .slider-input:focus-visible {
    outline: none;
    box-shadow: var(--tsr-shadow-focus);
}

.tsr-scope .switch-input:focus-visible ~ .switch-track {
    box-shadow: var(--tsr-shadow-focus);
}

.tsr-scope .checkbox-input:focus-visible ~ .checkbox-custom {
    box-shadow: var(--tsr-shadow-focus);
}

.tsr-scope .radio-option:has(input:focus-visible) {
    border-color: var(--tsr-accent);
    box-shadow: var(--tsr-shadow-focus);
}

/* ============================================= */
/* EMPTY STATE                                   */
/* ============================================= */

/* UNSCOPED EXCEPTION (the only one in this file): RepairStepRenderer also
   emits <div class="empty-step"> WITHOUT the .tsr-scope root and is outside
   this wave's file set -- scoping this rule would strip the repair empty
   state in both apps. Literal values because the repair copy has no token
   scope. Fold into .tsr-scope once RepairStepRenderer adopts the root class. */
.empty-step {
    text-align: center;
    padding: 60px 20px;
    color: #a8a6a0;
    font-size: 0.9rem;
}
